Reputation: 1121
Is it possible to bind Named instance based on the enclosing class? For ex: in the below sample, classes A and B will get DataStore instance injected. However, I need to have primary store as StoreA and secondary store as StoreB in the scope/context of class A but primary store as StoreC and secondary store as StoreD in the scope/context of class B. How can this be achieved?
class A {
@Inject
public A(DataStore dataStore) {
...
}
}
class B {
@Inject
public B(DataStore dataStore) {
...
}
}
class DataStore {
@Inject
public A(@Named("primary") Store primaryStore, @Named("secondary") Store store) {
...
}
}
bind(Store.class).annotatedWith(Names.named("primary")).to(StoreA.class);//for class A
bind(Store.class).annotatedWith(Names.named("secondary")).to(StoreB.class);//for class A
bind(Store.class).annotatedWith(Names.named("primary")).to(StoreC.class);//for class B
bind(Store.class).annotatedWith(Names.named("secondary")).to(StoreD.class);//for class B
Upvotes: 0
Views: 596
Reputation: 95634
This is sometimes known as the "robot legs" problem, as if building a robot with identical legs but differing left and right feet. Each Leg to bind a Foot, but the Foot requested depends on the Leg requested. In your case, each DataStore binds to a primary and secondary Store, but which Stores depends on the DataStore requested.
A Guice-injected instance can't be bound directly based on its target (a similar feature was rejected), but as mentioned in the FAQ you can use PrivateModule
to create a similar effect.
install(new PrivateModule() {
@Override public void configure() {
bind(Store.class).annotatedWith(Names.named("primary")).to(StoreA.class);
bind(Store.class).annotatedWith(Names.named("secondary")).to(StoreB.class);
expose(A.class);
}
});
install(new PrivateModule() {
@Override public void configure() {
bind(Store.class).annotatedWith(Names.named("primary")).to(StoreC.class);
bind(Store.class).annotatedWith(Names.named("secondary")).to(StoreD.class);
expose(B.class);
}
});
Consequently, @Named("primary") Store
will not be accessible outside of A
or B
(or its dependencies), but that makes sense; you're never defining a general Store
, but A
and B
each have the private bindings they need.
(Disclaimer: I didn't get a chance to test this, so it may need refinement.)
Upvotes: 1