amrk7
amrk7

Reputation: 1214

Guice inject different instance based on the parent instance annotation

I am using guice framework in my application. I have a scenario where a single class might require multiple instances of same interface C (but for different purposes) as shown in the example. I am trying to resolve this using the annotation facility in guice.

As shown in the example below, I want the config for ConcreteImpl also to be injected by guice. But the problem is the config for type1, type2 and type3 instances could be different. Assuming that I have the configurations for these instances apriori, is there a facility to inject them according to the context (denoted by annotation) of instance requesting the config?

    class A {
        @Inject
        public A(@Purpose1 C type1, @Purpose2 C type2, @Purpose3 C type3) {

        }
    }

    interface C {}

    class ConcreteImpl implements C {
        @Inject
        public ConcreteImpl(ConcreteImplConfig config) {}
    }

    class ConcreteImplConfig {
        String pty1;
        String pty2;
    }  

My module binding is like this -

    bind(C.class)
            .annotatedWith(Purpose1.class)
            .to(purpose1Cklass/**obtained from config**/);

    bind(C.class)
            .annotatedWith(Purpose2.class)
            .to(purpose2Cklass/**obtained from config**/);

    bind(C.class)
            .annotatedWith(Purpose3.class)
            .to(purpose3Cklass/**obtained from config**/);

And this is pretty much what I want to do

    bind(ConcreteImplConfig.class)
            .requestedThrough(Purpose1.class)
            .toInstance(purpose1config);

    bind(ConcreteImplConfig.class)
            .requestedThrough(Purpose2.class)
            .toInstance(purpose2config);

    bind(ConcreteImplConfig.class)
            .requestedThrough(Purpose3.class)
            .toInstance(purpose3config);

I already had a look at assisted inject, which can inject a factory and then we use factory.create(config) but I am not inclined to that as the contracts tend to become slightly uglier and all the more i have all the configs at the start of my application and should be able to inject them.

Upvotes: 3

Views: 1301

Answers (1)

Michael Lloyd Lee mlk
Michael Lloyd Lee mlk

Reputation: 14661

This is the Robot Leg Problem. You need to create a private module for C.

abstract class CModule extends PrivateModule {
    private final Class<? extends Annotation> annotation;

    CModule(Class<? extends Annotation> annotation) {
        this.annotation = annotation;
    }

    @Override protected void configure() {
        bind(C.class).annotatedWith(annotation).to(C.class);
        expose(C.class).annotatedWith(annotation);

        bindConfig();
    }

    abstract void bindConfig();
}

public static void main(String[] args) {
        Injector injector = Guice.createInjector(
                new CModule(Propsal1.class) {
                    @Override void bindConfig() {
                        bind(ConcreteImplConfig.class).toInstance(new ConcreteImplConfig());
                    }
                },
                new CModule(Propsal2.class) {
                    @Override void bindConfig() {
                        bind(ConcreteImplConfig.class).toInstance(new ConcreteImplConfig());
                    }
                },
                new CModule(Propsal2.class) {
                    @Override void bindConfig() {
                        bind(ConcreteImplConfig.class).toInstance(new ConcreteImplConfig());
                    }
                }
                );
    }

Upvotes: 2

Related Questions