I am injection multiple concretes of the same interface.
I figured out the Guide \"code it up\" convention.
My code currently spits out
[INFO
If you use Multibinder for map bindings, then you could bind each of the Shipper instances into a Map using MapBinder:
MapBinder multibinder = MapBinder.newMapBinder(
binder(), String.class, ShipperInterface.class);
multibinder.addBinding("FedEx").to(FedExShipper.class);
multibinder.addBinding("UPS").to(UpsShipper.class);
multibinder.addBinding("USPS").to(UspsShipper.class);
Then in your injected class you can inject a Map
:
private ShipperInterface FindShipperInterface(String
preferredShipperAbbreviation) {
ShipperInterface foundShipperInterface =
providerMap.get(preferredShipperAbbreviation).get();
}
You could also inject a Map
directly, but Multibinder handles the Provider indirection for free, which lets you avoid creating three ShipperInterface instances when only one will actually be necessary. Also, if your instance-selection code is more complicated than simply choosing based on a String from a set of implementations you know at compile time, you might still want a Factory implementation you write.
As a side note, ideally use @Inject annotations and bind(...).to(...) instead of toConstructor. This doesn't tie you to Guice, because @Inject
is defined in JSR-330, and you are adding annotations that you can choose not to use later. You can also write a @Provides
method in your AbstractModule, like so, which is no more fragile than your toConstructor
bindings:
@Provides UspsShipper provideUspsShipper(Log log) {
return new UspsShipper(log);
}
Use toConstructor
if and only if you are using legacy code, code you don't control, very restrictive code style rules, or AOP (which may be the case here). I've done so above for the sake of a concise example, but you can revert to toConstructor
if necessary.