Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overriding Binding in Guice

People also ask

What is binding in Guice?

A binding is an object that corresponds to an entry in the Guice map. You add new entries into the Guice map by creating bindings.

What is module in Guice?

Interface Module A module contributes configuration information, typically interface bindings, which will be used to create an Injector . A Guice-based application is ultimately composed of little more than a set of Module s and some bootstrapping code.


This might not be the answer you're looking for, but if you're writing unit tests, you probably shouldn't be using an injector and rather be injecting mock or fake objects by hand.

On the other hand, if you really want to replace a single binding, you could use Modules.override(..):

public class ProductionModule implements Module {
    public void configure(Binder binder) {
        binder.bind(InterfaceA.class).to(ConcreteA.class);
        binder.bind(InterfaceB.class).to(ConcreteB.class);
        binder.bind(InterfaceC.class).to(ConcreteC.class);
    }
}
public class TestModule implements Module {
    public void configure(Binder binder) {
        binder.bind(InterfaceC.class).to(MockC.class);
    }
}
Guice.createInjector(Modules.override(new ProductionModule()).with(new TestModule()));

See details here.

But as the javadoc for Modules.overrides(..) recommends, you should design your modules in such a way that you don't need to override bindings. In the example you gave, you could accomplish that by moving the binding of InterfaceC to a separate module.


Why not to use inheritance? You can override your specific bindings in overrideMe method, leaving shared implementations in configure method.

public class DevModule implements Module {
    public void configure(Binder binder) {
        binder.bind(InterfaceA.class).to(TestDevImplA.class);
        overrideMe(binder);
    }

    protected void overrideMe(Binder binder){
        binder.bind(InterfaceC.class).to(ConcreteC.class);
    }
};

public class TestModule extends DevModule {
    @Override
    public void overrideMe(Binder binder) {
        binder.bind(InterfaceC.class).to(MockC.class);
    }
}

And finally create your injector this way:

Guice.createInjector(new TestModule());

If you don't want to change your production module and if you have a default maven-like project structure like

src/test/java/...
src/main/java/...

You can just create a new class ConcreteC in your test directory using the same package as for your original class. Guice will then bind InterfaceC to ConcreteC from your test directory whereas all other interfaces will be bound to your production classes.


You want to use Juckito where you can declare your custom configuration for each test class.

@RunWith(JukitoRunner.class)
class LogicTest {
    public static class Module extends JukitoModule {

        @Override
        protected void configureTest() {
            bind(InterfaceC.class).to(MockC.class);
        }
    }

    @Inject
    private InterfaceC logic;

    @Test
    public testLogicUsingMock() {
        logic.foo();
    }
}