Search code examples
javadependency-injectionannotationsguiceguice-3

Guice @annotations approach similar to Guice MapBinder approach


I am new to Guice DI. And I would like to get my scenario clarified.

To put it simple, Is there any replacement of MapBinder through Guice @annotations?

My Scenario:

Interface A{}
Class A1 implements A{}
Class A2 implements A{}

I would like to Inject the implementation class of A as follows,

if(param = One) then Inject A1 to A
if(param = Two) then Inject A2 to A

I understand that the above could be done with MapBinder, but I would like to do it through annotations as follows,

Class A1 implements A
{     
@Inject(param = One)     
A1(){}    
}

Class A2 implements A
{     
@Inject(param = Two)     
A2(){}    
}

So making the class annotated with params could automatically picks and inject the class based on the parameter (One or Two).

Since @Inject cannot accept params, overriding @Inject would help in this scenario? if so, how do we do so?

Or Is this scenario could only be achieved through binding using MapBinder (The reason why I wouldn't want to use binder is that we would want to define the binding map of key value pair explicitly, but using annotations just simply annotate the implementation class with params - easier maintenance).

Thanks in advance.


Solution

  • To answer your follow-up questino, I believe what you are looking for are named injects. See this example:

    public class GuiceNamedTest extends AbstractModule {
    
        public static void main(String[] args) {
            Injector i = Guice.createInjector(new GuiceNamedTest());
            i.getInstance(InstaceOne.class);
            i.getInstance(InstaceTwo.class);
        }
    
        @Override
        protected void configure() {
            Bean beanOne = new Bean();
            beanOne.name = "beanOne";
    
            Bean beanTwo = new Bean();
            beanTwo.name = "beanTwo";
    
            bind(Bean.class).annotatedWith(Names.named("one")).toInstance(beanOne);
            bind(Bean.class).annotatedWith(Names.named("two")).toInstance(beanTwo);
    
            bind(InstaceOne.class);
            bind(InstaceTwo.class);
        }
    
    
        public static class Bean {
            String name;
        }
    
        public static interface A {}
    
        public static class InstaceOne implements A {
    
            @javax.inject.Inject
            public InstaceOne(@Named("one") Bean b1) {
                System.out.println(b1.name);
            }
        }
    
        public static class InstaceTwo implements A {
    
            @javax.inject.Inject
            public InstaceTwo(@Named("two") Bean b1) {
                System.out.println(b1.name);
            }
        }
    
    }
    

    Here, I am using annotatedWith to name my guice-handled instances. One of them corresponds to the String "one" and the other to "two", analogue to your example.

    I can then, in my implementations of A have specific injections of these beans using the @Named annotation.

    The result when running above code is:

    beanOne
    beanTwo
    

    As you can see, it injected the correct instance of my bean into the right implementation.

    Hope that helps,

    Artur