Search code examples
dependency-injectionguice

Guice Binding from Consumer Package


I am newbie for Guice and seeking help for the following use case :

I have developed one package say (PCKG) where the entry class of that package depends on other class like:

A : Entry point class --> @Inject A(B b) {}
B in turn is dependent on C and D like --> @Inject B(C c, D d) {}

In my binding module I am doing :

bind(BInterface).to(Bimpl);
bind(CInterface).to(CImpl);
...

Note I am not providing binding information for A as i want to provide its binding by its consumer class. (this is how the design is so my request is to keep the discussion on main problem rather than design).

Now my consumer class is doing like:

AModule extends PrivateModule {
    protected void configure() {
        bind(AInterface.class).annotatedWith(AImpl.class);
    }
}

Also in my consumer package:

.(new PCKGModule(), new AModule())

Q1. Am i doing the bindings correctly in consumer class. I am confused because when i am doing some internal testing as below in my consumer package:

class testModule {
    bind(BInterface).to(Bimpl); 
    bind(CInterface).to(CImpl)... 
}

class TestApp {
    public static void main(..) {
        Guice.createInstance(new testModule());
        Injector inj = Guice.createInstance(new AModule());
        A obj = inj.getInstance(A.class);
    }
}

It is throwing Guice creation exception.Please help me get rid of this situation. Also one of my friend who is also naive to Guice was suggesting that I need to create B's instance in AModule using Provides annotation. But i really didn't get his point.


Solution

  • Your main method should look like this:

    class TestApp {
    public static void main(..) {
        Injector injector = Guice.createInjector(new TestModule(), new AModule());
        A obj = injector.getInstance(A.class);
    }
    

    Note that the Java convention is for class names to have the first letter capitalised.

    I'm pretty sure your implementation of AModule isn't doing what you think it's doing either, but it's hard to be certain based on the information you've provided. Most likely, you mean to do this:

    bind(AInterface.class).to(AImpl.class)`
    

    There's no need to do anything "special" with A's binding. Guice resolves all the recursion for you. That's part of its "magic".

    annotatedWith() is used together with to() or toInstance(), like this:

    bind(AInterface.class).to(AImpl.class).annotatedWIth(Foo.class);
    bind(AInterface.class).to(ZImpl.class).annotatedWIth(Bar.class);
    

    Then you can inject different implementations by annotating your injection points, e.g.:

    @Inject
    MyInjectionPoint(@Foo AInterface getsAImpl, @Bar AInterface getsZImpl) {
        ....
    }
    

    It's worth also pointing out that you can potentially save yourself some boilerplate by not bothering with the binding modules (depending how your code is arranged) and using JIT bindings:

    @ImplementedBy(AImpl.class)
    public interface AInterface {
        ....
    }
    

    These effectively act as "defaults" which are overridden by explicit bindings, if they exist.