I have an interface that has 20 or so annotated implementations. I can inject the correct one if I know which I need at compile time, but I now need to dynamically inject on
In your module, load the bindings into the MapBinder
, then make your runtime parameters injectable as well. This example is based on the one in the documentation:
public class SnacksModule extends AbstractModule {
protected void configure() {
MapBinder<String, Snack> mapbinder
= MapBinder.newMapBinder(binder(), String.class, Snack.class);
mapbinder.addBinding("twix").to(Twix.class);
mapbinder.addBinding("snickers").to(Snickers.class);
mapbinder.addBinding("skittles").to(Skittles.class);
}
}
Then, in your object, inject the Map
and the parameter. For this example I will assume you've bound a java.util.Properties for your runtime parameters:
@Inject
public MyObject(Map<String, Provider<Snack>> snackProviderMap, Properties properties) {
String snackType = (String) properties.get("snackType");
Provider<Snack> = snackProviderMap.get(property);
// etc.
}
Note, with the same MapBinder
you can inject either a simple Map<String, Snack>
or a Map<String, Provider<Snack>>
; Guice binds both.
If all you want is to get an instance programmatically, you can inject an Injector. It's rarely a good idea--injecting a Provider<T>
is a much better idea where you can, especially for the sake of testing--but to get a binding reflectively it's the only way to go.
class YourClass {
final YourDep yourDep; // this is the dep to get at runtime
@Inject YourClass(Injector injector) {
YourAnnotation annotation = deriveYourAnnotation();
// getProvider would work here too.
yourDep = injector.getInstance(Key.get(YourDep.class, annotation));
}
}
If you're trying write a Provider that takes a parameter, the best way to express this is to write a small Factory.
class YourDepFactory {
@Inject @A Provider<YourDep> aProvider;
@Inject @B Provider<YourDep> bProvider;
// and so forth
Provider<YourDep> getProvider(YourParameter parameter) {
if (parameter.correspondsToA()) {
return aProvider;
} else if (parameter.correspondsToB()) {
return bProvider;
}
}
YourDep get(YourParameter parameter) {
return getProvider(parameter);
}
}