Question

New to Guice, so I'm looking into its expressive power. Suppose I have classes as follows:

public class Data {
    @Inject
    public Data(@Named("First") String first, @Named("Second") String second) { ... }
}

public class DataUser1 {
    @Inject
    public DataUser1(Data data) { ... }
}

public class DataUser2 {
    @Inject
    public DataUser2(Data data) { ... }
}

How do I create a module such that when I call injector.getInstance(DataUser1.class) I get something equivalent to new DataUser1(new Data("foo", "bar")) while having injector.getInstance(DataUser2.class) I get something equivalent to new DataUser2(new Data("foo2", "bar2"))?

Also related, how do I create a module for which I may need to get two instances of DataUser1, each of which using different Data values?

Was it helpful?

Solution

You use private modules for creating graphs of objects which are almost the same but differ in particular details.

public class DataUser1Module extends PrivateModule {
    @Override
    protected void configure() {
        bindConstant().annotatedWith(Names.named("First")).to("foo");
        bindConstant().annotatedWith(Names.named("Second")).to("bar");

        bind(Data.class);
        bind(DataUser1.class);

        expose(DataUser1.class);
    }
}

public class DataUser2Module extends PrivateModule {
    @Override
    protected void configure() {
        bindConstant().annotatedWith(Names.named("First")).to("foo2");
        bindConstant().annotatedWith(Names.named("Second")).to("bar2");

        bind(Data.class);
        bind(DataUser2.class);

        expose(DataUser2.class);
    }
}

Injector injector = Guice.createInjector(new DataUser1Module(), new DataUser2Module());
DataUser1 dataUser1 = injector.getInstance(DataUser1.class);
DataUser2 dataUser2 = injector.getInstance(DataUser2.class);

You do the same thing if you need two instances of DataUser1 with different Datas, but you use annotations to differentiate between them:

public class DataUser1Module1 extends PrivateModule {
    @Override
    protected void configure() {
        bindConstant().annotatedWith(Names.named("First")).to("foo");
        bindConstant().annotatedWith(Names.named("Second")).to("bar");

        bind(Data.class);
        bind(DataUser1.class).annotatedWith(Names.named("1")).to(DataUser1.class);

        expose(DataUser1.class).annotatedWith(Names.named("1"));
    }
}

public class DataUser1Module2 extends PrivateModule {
    @Override
    protected void configure() {
        bindConstant().annotatedWith(Names.named("First")).to("foo2");
        bindConstant().annotatedWith(Names.named("Second")).to("bar2");

        bind(Data.class);
        bind(DataUser1.class).annotatedWith(Names.named("2")).to(DataUser1.class);

        expose(DataUser1.class).annotatedWith(Names.named("2"));
    }
}

Injector injector = Guice.createInjector(new DataUser1Module1(), new DataUser1Module2());
DataUser1 dataUser11 = injector.getInstance(Key.get(DataUser1.class, Names.named("1"));
DataUser1 dataUser12 = injector.getInstance(Key.get(DataUser1.class, Names.named("2"));

This pattern is described in Guice FAQ.

See also these questions:

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top