2014-05-10

Guice Tutorial - 08 - Combine modules

Introduction

Single injector could be created from many modules, so dependecies could be separeted depends on their domain.


Combining modules

Suppose you have two modules. One describes classes using to talk with database and second provides classes for frontend. For database there are SessionFactory interface with its implementation - SessionFactoryImpl. The bining is defined in DatabaseModule.
public interface SessionFactory {}
public class SessionFactoryImpl implements SessionFactory {}
public class DatabaseModule extends AbstractModule {
    @Override
    protected void configure() {
        bind(SessionFactory.class).to(SessionFactoryImpl.class);
    }
}
Widget interface is bound to LabelWidget iFrontendModule .
public interface Widget {}
public class LabelWidget implements Widget{}
public class FrontendModule extends AbstractModule {
    @Override
    protected void configure() {
        bind(Widget.class).to(LabelWidget.class);
    }
}
We want to have injector, which uses this two modules, so we could create it in this way:
@Test
public void shouldJoinTwoDisjointModules(){
    //when
    Injector sut = Guice.createInjector(new DatabaseModule(), new FrontendModule());
    //then
    assertNotNull(sut.getInstance(SessionFactory.class));
    assertNotNull(sut.getInstance(Widget.class));
}
One constraint is that combined modules cannot have bindings for the same classes or interfaces.


Overriding modules

Suppose you have TestSessionFactoryImpl that you want to use in your tests.
public class TestSessionFactoryImpl implements SessionFactory{}
Binding for tests is defined in TestDatabaseModule.
public class TestDatabaseModule extends AbstractModule {
    @Override
    protected void configure() {
        bind(SessionFactory.class).to(TestSessionFactoryImpl.class);
    }
}
Tring to combine this module with your DatabaseModule ends with CreationException.
@Test(expected = CreationException.class)
public void shouldThrowExceptionWhenJoiningTwoModulesWithTheSameBindings(){
    Guice.createInjector(new DatabaseModule(), new TestDatabaseModule());
}
To not obtain CreationException you should tell Guice that you want to override bindings of DatabaseModule with your TestDatabaseModule.
@Test
public void shouldOverrideModule(){
    //when
    Injector sut = Guice.createInjector(Modules.override(new DatabaseModule()).with(new TestDatabaseModule()));
    //then
    assertEquals(TestSessionFactoryImpl.class, sut.getInstance(SessionFactory.class).getClass());
}

Conclusion

You can combine many modules during creation of injector, but only if they have no bindings for the same classes. If they have, you have to explicitly tell Guice which module overrides bindings in another module. Sources are available here.

No comments:

Post a Comment