muhuk's blog

Nature, to Be Commanded, Must Be Obeyed

May 28, 2015

Using Guice Effectively

Just a few tips on using Guice. If you are not familiar with dependency injection this post might make little sense[1]. I hope this will be useful for those of you who are interested in well organized and testable code.

Use a Module Hierarchy

Guice modules are modular. Just like we organize closely related classes in packages we can organize relevant bindings in different modules and then connect them either using module hierarchies or during injector creation. This doesn’t necessarily mean each package should have a module. Too many modules would make your code difficult to follow. Let’s take a look at how modules are combined and then discuss when it’s a good idea to use separate modules. Consider this class:

public class Foo {
    private final Bar bar;

    @Inject
    public Foo(final Bar bar) {
        this.bar = bar;
    }

    public Bar getBar() {
        return bar;
    }
}

If Bar had a zero arguments constructor Foo would just be injected one via reflection. But Bar is a bit more complex than that:

public class Bar {
    private final String message;

    public Bar(final String message) {
        this.message = message;
    }

    @Override
    public String toString() {
        return message;
    }
}

Slapping an @Inject onto Bar‘s constructor wouldn’t do. You probably don’t want to bind String class to any single value. How should message be constructed then? You can annotate message and provide a binding for that annotation. Let’s try a slightly different approach and bind Bar to an instance[2]:

public class ChildModule extends AbstractModule {
    @Override
    protected void configure() {
        bind(Bar.class).toInstance(new Bar("from ChildModule"));
    }
}

This module is called ChildModule because we will install it within another module:

public class ParentModule extends AbstractModule {
    @Override
    protected void configure() {
        install(new ChildModule());
        bind(Foo.class);
    }
}

Here is the main class:

public class Main {
    public static void main(final String[] args) {
        final Injector injector = Guice.createInjector(new ParentModule());
        final Foo foo = injector.getInstance(Foo.class);
        System.out.println(foo.getBar());
    }
}

When you run this code it outputs "from ChildModule". When we installed ChildModule, Bar became available for injection in ParentModule. So would any other binding ChildModule could have had. If some bindings needed to construct Bar were not meaningful outside of ChildModule you can use a PrivateModule to hide them from ParentModule.

Sub-modules like ChildModule above can be created for each adapter in a project. Adapters shouldn’t have knowledge of each other which makes them a good candidate to start grouping bindings.

Libraries can also provide their own modules to be integrated with modules of applications. To avoid forcing Guice as a dependency, libraries can offer their modules as separately. It is possible to do @Injectless bindings using providers. This might be a good time to remind createInjector accepts a variable number of module instances:

Injector injector = Guice.createInjector(
    new ApplicationModule(),
    new LibraryFooModule(),
    new LibraryBarModule()
);

Hide the Config

If you application reads configuration from text files or environment you probably have a class that provides this information. It might seem like the obvious thing to inject this class directly. But it would create an unnecessary dependency for your class that’s being injected. What is worse sometimes configuration providers are not type-safe.

I would suggest directly injecting configuration values (like the URL of some remote service’s endpoint or number of threads to be started) and hiding the the origin of them from your classes. Dependency injection is configuring your application’s object graph, it already is configuration. There is no need to create a separate category of configuration just because the data comes from some file.

Hiding the config not only makes your components more loosely coupled and makes testing easier, it also gives you more static safety. Avoiding runtime type casts in statically typed languages as much as possible would allow you to do more designing and coding and less debugging.

It might be a good idea to create a sub-module that contains bindings for configuration values. See the first tip.

If some class needs too many configuration values to be passed in its constructor you might create a data object that provides only what this it needs. In my experience classes rarely need more than three config values, if a lot more is needed perhaps the class is doing too much[3].

By the way, it might be tempting to dynamically create bindings based on configuration. I would advise against that. An application’s object graph is tied to the codebase, not the execution environment. It should be known at compile-time and it should be type checked. At least most of it. Plugins are exceptions.

Type Checked Annotations

High level layers of your code might only be injecting service objects based on interfaces. But lower levels will probably be needing more and more primitives. Consider following class:

public class Box {
    private final int width;
    private final int height;
    private final int depth;

    @Inject
    public Box(final int width, final int height, final int depth) {
        this.width = width;
        this.height = height;
        this.depth = depth;
    }

    public int surfaceArea() {
        return (width * height + width * depth + height * depth) * 2;
    }

    public int volume() {
        return width * height * depth;
    }
}

Annotating the constructor with @Inject isn’t enough. Guice would see three ints it doesn’t know how to inject. We must distinguish them somehow. @Named annotation is one way to do this:

@Inject
public Box(@Named("width") final int width,
           @Named("height") final int height,
           @Named("depth") final int depth) {
    this.width = width;
    this.height = height;
    this.depth = depth;
}

And then we can bind our values with matching strings:

bindConstant().annotatedWith(Names.named("width")).to(40);

Although @Named is convenient, using string literals ubiquitously in a large codebase will inevitably maintenance issues. Instead we can create our own annotations:

@Inject
public Box(@Width final int width,
           @Height final int height,
           @Depth final int depth) {
    this.width = width;
    this.height = height;
    this.depth = depth;
}

;; In Height.java:

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import com.google.inject.BindingAnnotation;

@BindingAnnotation
@Target({ PARAMETER, METHOD })
@Retention(RUNTIME)
public @interface Height {
}

;; In the module:

bindConstant().annotatedWith(Height.class).to(40);

@Height here is just another BindingAnnotation. Admittedly it’s a lot more typing than using @Named. But, unless your codebase is @Inject-less (see above), the code is cleaner without the magic string literals.


If you have more Guice tips, or comments about these feel free to drop me an .

[1]In that case I would strongly recommend watching this video.
[2]This is lazy but not really inappropriate since Bar has no mutable state.
[3]There is no magic number, I am not saying three configuration values or your code sucks. It’s not even a rule but there can be exceptions.

If you have any questions, suggestions or corrections feel free to drop me a line.