I am a software engineer at Google on the Android project and the creator of the Java testing framework TestNG. When I'm not updating this weblog with various software-related posts or speaking at conferences, I am busy snowboarding, playing squash, tennis, golf or volleyball or scuba diving. Cedric is a DZone MVB and is not an employee of DZone and has posted 84 posts at DZone. You can read more from them at their website. View Full User Profile

You've Been Implementing main() Wrong All This Time

03.26.2012
| 9357 views |
  • submit to reddit

Since the very early days of Java (and C-like languages overall), the canonical way to start your program has been something like this:

public class A {
  public static void main(String[] args) {
    new A().run(args);
  }

  public void run(String[] args) {
    // Your application starts here
  }
}

If you are still doing this, I’m here to tell you it’s time to stop.

Letting go of ‘new’

First, install Guice in your project:

<dependency>
  <groupId>com.google.inject</groupId>
   <artifactId>guice</artifactId>
   <version>3.0</version>
</dependency>

and then, modify your main method as follows:

public class A {
  public static void main(String[] args) {
    Injector.getInstance(A.class).run(args);
  }
}

So, what does this buy you exactly?

You will find a lot of articles explaining the various benefits of Guice, such as being able to substitute different environments on the fly, but I’m going to use a different angle in this article.

Let’s start by assuming the existence of a Config class that contains various configuration parameters. I’ll just hardcode them for now and use fields to make the class smaller:

public class Config {
  String host = "com.example.com";
  int port = 1234;
}

This class is a singleton, it is instantiated somewhere in your main class and not used anywhere else at the moment. One day, you realize you need this instance in another class which happens to be deep in your runtime hierarchy, which we will call Deep. For example, if you put a break point in the method where you need this config object, your debugger would show you stack frames similar to this:

com.example.A.main()
com.example.B.f(int, String)
com.example.C.g(String)
com.example.Deep.h(Foo, int)

The easy and wrong way to solve this problem is to make the Config instance static on some class (probably A) and access it directly from Deep. I’m hoping I don’t need to explain why this is a bad idea: not only do you want to avoid using statics, but you also want to make sure that each object is exposed only to objects that need them, and making the Config object static would make your instance visible to your entire code base. Not a good thing.

The second thought is to pass the object down the stack, so you modify all the signatures as follows:

com.example.A.main()
com.example.B.f(int, String, Config)
com.example.C.g(String, Config)
com.example.Deep.h(Foo, int, Config)

This is a bit better since you have severely restricted the exposure of the Config object, but note that you are still making it available to more methods than really need to: B#f and C#g have really nothing to do with this object, and a little sting of discomfort hits you when you start writing the Javadoc:

public class C {
  ...
  /**
   * @param config This method doesn't really use this parameter,
   * it just passes it down so Deep#h can use it.
   */
  public void g(String s, Config config) {

Unnecessary exposure is actually not the worst part of this approach, the problem is that it changes all these signatures along the way, which is certainly undesirable in a private API and absolutely devastating in a public API. And of course, it’s absolutely not scalable: if you keep adding a parameter to your method whenever you need access to a certain object, you will soon be dealing with methods that take ten parameters, most of which they just pass down the chain.

Here is how we solve this problem with dependency injection (performed by Guice in this example, but this is applicable to any library that implements JSR 330, obviously):

public class Deep {
  @Inject
  private Config config;

and we’re done. That’s it. You don’t need to modify the Config class in any way, nor do you need to make any change in any of the classes that separate Deep from your main class. With this, you have also minimized the exposure of the Config object to just the class that needs it.

Injecting right

There are various ways you can inject object into your class but I’ll just mention the two that, I think, are the most important. I just showed “field injection” in the previous paragraph, but be aware that you can also prefer to use “constructor injection”:

public class Deep {
  private final Config config;

  @Inject
  public Deep(Config config) {
    this.config = config;
  }

This time, you are adding a parameter to the constructor of your Deep class (which shouldn’t worry you too much since you will never invoke it directly, Guice will) and you assign the parameter to the field in the constructor. The benefit is that you can declare your field final. The downside, obviously, is that this approach is much more verbose.

Personally, I see little point in final fields since I have hardly ever encountered a bug that was due to accidentally reassigning a field, so I tend to use field injection whenever I can.

Taking it to the next level

Obviously, the kind of configuration object I used as an example if not very realistic. Typically, a configuration will not hardcode values like I did and will, instead, read them from some external source. Similarly, you will want to inject objects that can’t necessarily be instantiated so early in the lifecycle of your application, such as servlet contexts, database connections, or implementations of your own interfaces.

This topic itself would probably cover several chapters of a book dedicated to dependency injection, so I’ll just summarize it: not all objects can be injected this way, and one benefit of using a dependency injection framework in your code is that it will force you to think about what life cycle category your objects belong to. Having said that, if you want to find out how Guice can inject objects that get created at a later time in your application life cycle, look up the Javadoc for the Provider class.

Wrapping up

I hope this quick introduction to dependency injection piqued your interest and that you will consider using it in your project since it has so much more to offer than what I described in this post. If you want to learn more, I suggest starting with the excellent Guice documentation.

 

Published at DZone with permission of Cedric Beust, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Christopher Brown replied on Mon, 2012/03/26 - 6:56am

Hi,

Implementing "Config" here using an OSGi framework as an OSGi service (the complexity is roughly equivalent) is another versatile alternative.  The "client" class would query the service registry in OSGi for available implementations (returning 0, 1, or n implementations at a given time, including versioning and runtime reloading), the querying logic is no more a dependency than the @Inject annotation.

 When you refer to being able to substitute "on the fly", are you referring to an ability to hotswap or substitute implementations without restarting the application?

Thanks

 

Nir Moav replied on Mon, 2012/03/26 - 10:35am

Excellent post.

I agree very much with this approach as well.

The power of DI frameworks like Guice and their advantages are already well known.

Anyone who ever used the Spring framework for instance should understand the

great benefits. 

 

You can check this post about how to bring Guice to your front end:

http://tech-drum.blogspot.com

 

 

Dale Wyttenbach replied on Mon, 2012/03/26 - 11:52am

Don't you have to do something like this?

Injector injector = Guice.createInjector(); 

zim 2001 replied on Mon, 2012/03/26 - 3:45pm

IMHO this example is not appropriate to demonstrate the forces of DI.

The problem you expose can be handled simply with a basic and classical "public static getInstance()..." that does the job with no extra libraries and automagical injection. In such a context DI appears overdesigned and pointless to me, sorry.

Donald Mcronald replied on Mon, 2012/03/26 - 4:14pm

I've had a few false starts with Guice.  All the articles and books I've read are like this one.  They tell you how awesome Guice is at injecting resources deep into your component hierarchy, but none of them explain how to create a new instance of, for example, Deep way down in that hierarchy.

Does B use an injector to instantiate C and then C uses an injector to instantiate Deep?  IIRC the Guice docs say not to create Injectors for every class, so do B and C need a reference to a global Injector?  How do I keep Guice specific code out of B and C?

Every time I give Guice another try I end up wanting to litter Guice specific code everywhere and that's the point where I toss it aside because the whole thing smells bad.  That may be misuse on my part, but there seems to be a lot of temptation for beginners to trade one problem for another.

matt inger replied on Mon, 2012/03/26 - 8:54pm in response to: zim 2001

because singletons present a whole host of issues with testing, swapping implementations.  The common approach to a singleton is this:

 public class MySingleton {
  private MySingleton() { }
  private MySingleton instance;
  public static synchronized MySingleton getInstance() {
    if (instance == null) { instance = new MySingleton(); }
    return instance; 
  } 

 But what happens when MySingleton has multiple implementations for different environments?  A good example might be a configuration interface.  Implementations might consist of hardcoded values (for testing), a .properties file (for command line programs), or servlet context parameters (for web based apps). 

Now your singleton is no longer as simple, since it has to know what environment you are in, and construct the right instance.  Especially in the web case, you need the ServletContext class, which means a hardcoded dependency on the servlet api even for things like command line programs that don't need those classes.

In this case, it's much simple to use an IOC container like spring, (forgive me, since I don't know guice) .  Your spring file for a specific module might look like this:

<bean id="SomeService" class="..." p:config-ref="configuration" />

And in  a main context file, which differs for each environment, and the main program (or web.xml for web apps) would include the right main context file (and with spring 3.0, you could use profiles as well instead of different context files):

<bean id="configuration" class="ServletConfiguration" />

or

<bean id="configuration" class="MemoryConfiguration" />

and so forth.

I personally find testing and coding much easier when you leave the wiring details to an IOC container. 

zim 2001 replied on Thu, 2012/03/29 - 4:43am in response to: matt inger

I agree with you on IOC benefits : loose coupling, easier unit testing and so on.

But instead of justify the use of Guice with such arguments; the article starts with :

not only do you want to avoid using statics, but you also want to make sure that each object is exposed only to objects that need them, and making the Config object static would make your instance visible to your entire code base. Not a good thing.

Which I do not feel convincing at all for new people to adopt Guice (or any other DI framework such as Spring).

Jammer Man replied on Wed, 2012/04/04 - 1:08pm

My philosophy: just because you can do something with a programming language and/or framework doesn't mean you should.  Simple is always the best solution.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.