Reputation: 59
I have an interface A with multiple implementations say B, C and D. I am using guice assisted inject to create these classes. Classes B and C use the same assister parameters(say b, c) in constructor while D has one different parameter(say d). The way I implementing this is have a factory AFactory with 2 methods: create(int b, int c) and createD(int d) In my module, I have created a PrivateModule to bind the concrete class to factory.
The code looks like this:
public static PrivateModule getAFactoryModule(final String factoryBindingKey,final Class<? extends A> targetClassToCreate) {
return new PrivateModule() {
@Override
public void configure() {
install(new FactoryModuleBuilder().implement(
A.class, targetClassToCreate).build(
AFactory.class));
bind(AFactory.class).annotatedWith(Names.named(factoryBindingKey)).to(
Key.get(AFactory.class));
expose(Key.get(AFactory.class, Names.named(factoryBindingKey)));
}
};
}
I call PrivateModule like this:
install(getAFactoryModule("B", B.class));
install(getAFactoryModule("C", C.class));
install(getAFactoryModule("D", D.class));
But, this gives an error saying:
com.guice.test.B has @AssistedInject constructors but none of them match the parameters in method com.guice.test.AFactory.createD(). Unable to create assisted inject
com.guice.test.C has @AssistedInject constructors but none of them match the parameters in method com.guice.test.AFactory.createD(). Unable to create assisted inject
com.guice.test.D has @AssistedInject constructors but none of them match the parameters in method com.guice.test.AFactory.create(). Unable to create assisted inject
It seems Guice is trying to use different create methods than what is expected. Any idea how this can be resolved? Any pointers would be appreciated!
Thanks!
Upvotes: 1
Views: 2718
Reputation: 95614
It sounds like you are doing something unsafe—leaving some of your factory methods unresolved—and Guice is confused. Basically, FactoryModuleBuilder is generating the following code:
@Named("B") public class GeneratedBClass implements AFactory {
A create(int b, int c) { return new B(...); }
A create(int d) { /* no implementation! */ }
}
@Named("C") public class GeneratedBClass implements AFactory {
A create(int b, int c) { return new C(...); }
A create(int d) { /* no implementation! */ }
}
@Named("D") public class GeneratedBClass implements AFactory {
A create(int b, int c) { /* no implementation! */ }
A create(int d) { return new D(...); }
}
Those three missing implementations are the reason Guice is complaining: Guice can't find a good implementation for those, and figures that you'll want them wired up. Beyond Guice, though, you've got a very dangerous API designed: Depending on your configuration, one of your methods will work, and one cannot work—which is more dangerous than DI was designed for.
I would either switch your configuration to only switch "B" and "C", and have both of those expose a "D":
public interface AFactory {
@Named("BorC") A create(int B, int C);
@Named("D") A create(int D);
}
install(new FactoryModuleBuilder()
.implement(A.class, Names.named("BorC"), targetClassToCreate)
.implement(D.class, Names.named("D"), D.class)
.build(AFactory.class));
...or, because you should know at compile time whether you're going to call the two-argument or one-argument constructor, just switch D to its own factory:
public interface DFactory {
D create(int D);
}
// If DFactory creates an A, you need implement(). Otherwise, this works.
install(new FactoryModuleBuilder().build(DFactory.class));
Upvotes: 3