Guice Hello World

March 12, 2007

A new project called Guice (pronounced Juice, but starts with a G instead of J because it's Googlerrific) has been created. Guice aims to be a better Dependency Injection (DI) framework for Java. The de facto DI framework for Java is currently Spring. Spring provides a lot of things besides DI, but I think DI is it's main selling point. I often use Spring in projects only for it's DI. I use Stripes as my Web MVC framework and Hibernate as my ORM framework, so I don't need Spring's MVC layer or JDBC Template. I do use Spring's declarative transaction management and hibernate configuration features, but that's only because once you start using Spring for DI, it's easy to use those features as well, but they could be easily replaced.

The main disadvantage of Spring, in my opinion, is the amount of XML files that you have to create to configuration you application. The thing I dislike most about the XML configuration is that it is not type safe, and just like Bob Lee says:

I'm using a strongly typed language; why would I want to throw all of this perfectly good type information away? If I wanted that, I'd use Ruby.

I don't think he meant that statement as a knock against Ruby, he's just saying that if you are programming in Java, then you want to use type safety as much as possible. Annotations and Generics, features added to Java in Java 5, can allow you to do that, and Guice aims to provide dependency injection via Annotations rather than XML.

So I decided to take a look at Guice, and although the documentation is pretty good, it doesn't have a working "Hello World" type example to get you going, so I figured I would provide one here. I encourage you to play along at home.

First, download Guice, setup a new project in your favorite IDE, and add guice-1.0.jar to your classpath. What we're going to do is create a basic domain model object, Foo, and a DAO-like Manager for Foo, and then create a controller that depends on the FooManager, and has that dependency set using Guice. So here we go. Create the Foo class:

public class Foo {

    private Long id;
    private String name;

    //Generate and getters/setters in your IDE

}

Then create the interface for the FooManager:

public interface FooManager {

    public Foo get(Long id);
    public void save(Foo foo);

}    

Then create an implementation of the FooManager. In real life, you might implement this with an ORM framework like Hibernate, but this simple little thing serves the purpose for this example:

public class FooManagerImpl implements FooManager {

    private static Long fooSequence = 1l;
    private static final Map<Long, Foo> foos = new HashMap<Long, Foo>();

    public Foo get(Long id) {
        return foos.get(id);
    }

    public void save(Foo foo) {
        if(foo == null) return;
        if(foo.getId() == null) {
            foo.setId(fooSequence);
            fooSequence++;
        }
        foos.put(foo.getId(), foo);
    }
}

And for the last part of our app, we'll create a controller that calls our manager. This controller is sort of like what a controller in a web app might be like:

public class FooController {

    private FooManager fooManager;

    //----- Controller Actions -------------------------------------------------
    public Foo create(String name) {
        Foo foo = new Foo();
        foo.setName(name);
        fooManager.save(foo);
        return foo;
    }

    public Foo retrieve(Long id) {
        return fooManager.get(id);
    }

    //----- Getters/Setters ----------------------------------------------------
    public FooManager getFooManager() {
        return fooManager;
    }

    @Inject
    public void setFooManager(FooManager fooManager) {
        this.fooManager = fooManager;
    }

}

You can see that with the annotation Inject on the fooManager setter, we are asking Guice to inject a fooManager instance into our controller. Continuing with the web app like architecture of our app, we'll create a dispatcher. In a real app, this would be the FrontController responsible for directing the request to be handled by the appropriate controller action, but for our simple app, we'll just hard code 2 controller action methods to be called:

public class FooDispatcher {

    public static void main(String[] args) {

        FooController controller = new FooController();
        Injector injector = Guice.createInjector(new FooModule());
        injector.injectMembers(controller);

        //Our action is now injected with a FooManager, so let's use it
        Foo foo = controller.create("Bar");
        Foo bar = controller.retrieve(foo.getId());
        System.out.println("bar.name => "+bar.getName());

    }

}

As you can see here, we've now got some Guice specific code. First we create an injector using the FooModule. The FooModule is a class we create that serves as the configuration for Guice, we'll get to that in a minute. The creation of this injector is something that you would do once, probably upon application startup. Then, we ask the injector to inject our controller instance with its dependencies. The simple Inject annotation we added on the setFooManager method of our controller is all the info the injector needs to set up our controller. Next you see we call 2 action methods, one to create a new Foo instance, and then another to retrieve it.

So let's look at the FooModule, which is where we do our Guice configuration:

public class FooModule extends AbstractModule {

    protected void configure() {
        bind(FooManager.class)
            .to(FooManagerImpl.class)
            .in(Scopes.SINGLETON);
    }

}

What this says is that when something needs a FooManager injected into it, use a singleton instance of FooManagerImpl to fulfill that dependency. We can actually use annotations to further simplify this configuration. First, we add the ImplementedBy annotation to the FooManager interface:

@ImplementedBy(FooManagerImpl.class)
public interface FooManager {

    public Foo get(Long id);
    public void save(Foo foo);

}

This basically says to Guice that we want FooManagerImpl to be the default implementation class for FooManager. Also, we can specify that by default we want FooManagerImpl to be a singleton:

@Singleton
public class FooManagerImpl implements FooManager {

    private static Long fooSequence = 1l;
    private static final Map<Long, Foo> foos = new HashMap<Long, Foo>();

    public Foo get(Long id) {
        return foos.get(id);
    }

    public void save(Foo foo) {
        if(foo == null) return;
        if(foo.getId() == null) {
            foo.setId(fooSequence);
            fooSequence++;
        }
        foos.put(foo.getId(), foo);
    }
}

Now, we can modify our module to look like this:

public class FooModule extends AbstractModule {

    protected void configure() {
        bind(FooManager.class);
    }

}

An now when we re-run our FooDispatcher, every thing still works. In real life, there would be some core mechanism in the web app framework to handle creating the injector and injecting dependencies into the controller instances, and I'm sure it would be fairly trivial to implement that into Stripes.

Although some people don't think Guice is going to replace Spring, I think for projects where Spring is being used mostly for DI, we will see Guice or something like it start to replace Spring. I also predict that in response to this, Spring will be forced into incorporating an annotation-based configuration mechanism into its core codebase in order to remain popular in the oncoming wave of Annotation based "zero" configuration frameworks like Stripes, Struts 2 and Hibernate.

UPDATE: Monday, March 12, 5:18pm

Thanks to a tip from Bob, I've discovered that once you have every thing configured by annotations, as we do at the end of this example, you can completely remove the FooModule, which gives you the code like this in the dispatcher:

public class FooDispatcher {

    public static void main(String[] args) {

        FooController controller = new FooController();
        Injector injector = Guice.createInjector();
        injector.injectMembers(controller);

        //Our action is now injected with a FooManager, so let's use it
        Foo foo = controller.create("Bar");
        Foo bar = controller.retrieve(foo.getId());
        System.out.println("bar.name => "+bar.getName());

    }

}

The point is that for any class that you can configure with annotations, you don't need to explicitly define them in a module, or anywhere. So take an app with 50 different manager classes, all you would have to do is create a manager interface, annotate it as a singleton, and then create the default implementation. Compare that with a minimum of 50 bean entries in a Spring context configuration XML file, and you can see how Guice can really start to simplify your configuration.

Posted in Technology | Tags Spring, Hibernate, Stripes, Java, DependencyInjection, Guice | 28 Comments