I'm having trouble finding how to have a "dynamic AssistedInject". What i mean by that is i would like to provide to the factory the implementing class name it needs to use at runtime based on a parameter. Here's what i currently have:
interface Letter {}
abstract class ALetter implements Letter {
public ALetter(T1 t1, T2 t2) {...}
}
class A implements Letter {
public static final NAME = "A";
@Inject
public A(@Assisted T1 t1, T2 t2) { super(t1, t2); }
}
class B implements Letter {
public static final NAME = "B";
@Inject
public B(@Assisted T1 t1, T2 t2) { super(t1, t2); }
}
I would like to be able to load either A or B based on their name considering I would have T1 but I would need T2 injected. It may look something like:
class MyClass {
@Inject
public MyClass(RequestData data, MyConfig config, ILetterFactory letterFactory) {
Letter letter = letterFactory.get(data.getLetterName(), config.getT2());
}
}
And i would have configured ILetterFactory using something like:
install(new FactoryModuleBuilder().build(ILetterFactory.class));
But I know this currently would not work as the lettername isn't a real parameter of my constructor and Guice just doesn't work like that. It should give you an idea of what I want though.
The only solution I've currently found does not use Guice: I have my own factory that resolves the class constructor based on the name (through a Map<String, Constructor>
), and calls newInstance
providing it with the appropriate params (no injection at all besides in the factory itself).
Is there a way to use Guice to avoid creating that factory myself ? Thanks
FactoryModuleBuilder isn't as powerful as you think it is—it has no provision to switch between implementations, and is only used for mixing injected dependencies with other constructor arguments. Luckily, Guice makes your factory easy to write. What it sounds like you're looking for is an implementation of this interface:
Choice one is to let Guice provide your instances with a Provider, which is most useful if your Letters have widely differing deps, or if your deps list is long or changes often. If A and B need assisted dependencies, replace
Provider<A>
withA.Factory
that you've bound through FactoryModuleBuilder.With choice two, you take the responsibility of creating a new instance from Guice. It requires more maintenance if your deps list changes, and doesn't play as nicely with AOP and other similar features, but may be a little less work if your Letters need assisted parameters and a small set of similar deps: