2014-05-01

Guice Tutorial - 07 - Module

Introduction

So far, we was using only annotations and creating injector without giving any parameters. It could be possible, because we was using classes defined by us or having no-arg constructor. But sometimes we have to use classes from external library, which do not meet these conditions. With the help comes to us Module.

Module

The module is an interface which has only one method - configure, where bindings could be defined. Binding is a form, which tells injector how to obtain instance of class that we ask for. It looks like this: bind(class).toSth(...). The best way to have defined bind method in your module is extend AbstractModule class.
public class MyModule extends AbstractModule{
    @Override
    protected void configure() {
        //...
    }
}
Module is the main definition for injector and when something is undefined then it also use bindings defined via annotations. Important is that module always overrides annotations, for example when class has annotations and module defines binding for it, then module binding is used.

Binding to constructor

First binding tells how to obtain class using constructor and there is method toConstructor where you could pass a constructor:
try {
    bind(FirstClass.class).toConstructor(FirstClass.class.getConstructor(Dependency.class));
} catch(NoSuchMethodException e) {
    // But i know it exists
    e.printStackTrace();
}
FirstClass class (and almost all class used in examples) looks like this:
public class FirstClass {
    private Dependency dependency;

    public FirstClass(final Dependency dependency) {
        this.dependency = dependency;
    }
}
It is not so easy to define constructor in this way so if I could I use Inject annotation, which means the same.
public class SecondClass {
    private Dependency dependency;

    @Inject
    public SecondClass(final Dependency dependency) {
        this.dependency = dependency;
    }
}

Binding to provider

We are using Provider to prepare class and module changes nothing, but we could replace ProvidedBy annotation in class with toProvider method in module:
bind(ThirdClass.class).toProvider(ThirdClassProvider.class);

Binding to instance

Of course, you could create one instance of class and want to pass it to every class, which could use it. We bind it using toInstance.
bind(FourthClass.class).toInstance(new FourthClass(new Dependency()));

Binding to concrete implementation

When we want to inject concrete implementation for interface or abstract class we have been using ImplementedBy annotation. In module we could simply use to and tell which class we want to bind to it. Of course, we have to define how to obtain this class (in module or via annotations).
bind(SomeClass.class).to(FifthClass.class);

Using scope

We could define that we want the class to be the singleton via annotation Singleton, so in module we should have this possibility too. And we have. We could tell in which scope class should be using method in at the end of each binding. For example:
try {
    bind(SixthClass.class).toConstructor(SixthClass.class.getConstructor(Dependency.class)).in(Singleton.class);
} catch(NoSuchMethodException e) {
    e.printStackTrace();
}

Conclusion

Annotations and module could be used to describe how injector should create instances of classes that we ask for. But annotations could be placed only on our classes, while module could describe creation for each class and is more important for Injector than annotations. 
All sources are available here.

No comments:

Post a Comment