Reputation: 227
I'm trying to learn Guice, but the following scenario seems hard. Let's say I have classes A,B and C. I should be able to do the following (Note that this example is somewhat simplified to the actual case):
When B creates C, the dependency B of C must be the same instance, i.e. from C's point of view, the B is singleton.
I have tried creating child injectors:
private static class MainModule extends AbstractModule{
@Override
protected void configure() {
bind(A.class).in(Singleton.class);
}
@Provides
B createB(Injector injector){
return injector.createChildInjector(new SubModule()).getInstance(B.class);
}
}
private static class SubModule extends AbstractModule{
@Override
protected void configure() {
bind(B.class).in(Singleton.class);
bind(C.class);
}
}
public static void main(String[] args) {
Injector injector = Guice.createInjector(new MainModule());
A a = injector.getInstance(A.class);
B b1 = a.getB();
B b2 = a.getB();
// all following C's are different instances
C b1c1 = b1.getC(); //this has b1 and a
C b1c2 = b1.getC(); //this has b1 and a
C b2c1 = b2.getC(); //this has b2 and a
C b2c2 = b2.getC(); //this has b2 and a
}
But then Guice gives errors that B is already bound (The Provides method in MainModule). Therefore I would need to override the B binding of MainModule, but this seems to be impossible using child injectors.
The problem is solvable by using multiple injectors, e.g. create new one for createB method and inject A as parameter, but it seems that using multiple injectors is not best practice.
EDIT: Added comments to C instances to clarify which instance of B they should have
Upvotes: 2
Views: 1306
Reputation: 227
I'll post this as an answer, it's more like workaround than full solution, but probably good enough for my application anyway:
private static class MainModule extends AbstractModule{
@Override
protected void configure() {
bind(A.class).in(Singleton.class);
bind(SubModule.class).in(Singleton.class);
}
@Provides
B createB(Injector injector){
SubModule m = injector.getInstance(SubModule.class);
return Guice.createInjector(m).getInstance(B.class);
}
}
private static class SubModule extends AbstractModule{
private final A a;
@Inject
public SubModule(A a) {
this.a = a;
}
@Override
protected void configure() {
bind(A.class).toInstance(a);
bind(B.class).in(Singleton.class);
bind(C.class);
}
}
First I tought that most of the bindings would be in the MainModule, but I guess they can be moved to the SubModule anyway if they are only used in the context of B (and route others like I did with A). This is mostly similar to the answer of linked question: Dependency injection: Scoping by region (Guice, Spring, Whatever) but I create new top-level injector because it seems I can't bind B in both modules, or I might miss something here..
(First time doing this, not sure if this is correct way to do post a work-around as own answer)
Upvotes: 1