I am trying to create a Dagger in Java code (not Android) for an Interface which has two or more implementations. I was able to do it successfully with CDI using javax libraries but I want to use Dagger this time around as per my project need. I am not able to call right implementation or event resolve the dependency during compilation. I am getting error with either multiple binding or missing binding.
I am new to Dagger2 and trying to figure this out.
So I started creating an interface first:
public interface Engine {
public startEngine();
}
Engine has two implementations Petrol and Diesel
public class PetrolEngine implements Engine {
@Inject
public PetrolEngine(){}
@Override
public startEngine() {
System.out.println("Petrol Engine Start");
}
}
public class DieselEngine implements Engine {
@Inject
public DieselEngine(){}
@Override
public startEngine() {
System.out.println("Diesel Engine Start");
}
}
Module created as
@Module
public class EngineModule {
@Provides
@IntoMap
@StringKey("Petrol")
public Engine providesEngine(PetrolEngine petrolEngine){
return petrolEngine;
}
@Provides
@IntoMap
@StringKey("Diesel")
public Engine providesEngine(DieselEngine dieselEngine){
return dieselEngine;
}
}
Component
@Component(module = EngineModule.class)
public interface EngineComponent {
EngineService providesEngineService();
}
Finally the Service that will call either Petrol or Diesel
public call EngineService {
private Engine engine;
@Inject
public EngineService(Engine engine) {
this.engine = engine;
}
public void getEngineInstance() {
//Some code to get the Petrol/Diesel Engine Instance
}
}
In EngineService, rather than injecting Engine, you'll need to inject a Map<String, Engine>
or a Map<String, Provider<Engine>>
. As in the docs, the Map<String, Provider<Engine>>
is "useful when you don’t want all of the values to be instantiated because you’re going to extract one value at a time, or because you want to get a potentially new instance of each value each time you query the map".
public call EngineService {
private final Map<String, Engine> engineMap;
@Inject
public EngineService(Map<String, Engine> engineMap) {
this.engineMap = engineMap;
}
public void getEngineInstance() {
engineMap.get("Petrol"); // to get a PetrolEngine
engineMap.get("Diesel"); // to get a DieselEngine
}
}
Note that in a realistic example, if the only practical binding for @StringKey("Petrol") Engine
is PetrolEngine
, you might as well inject PetrolEngine directly, where @StringKey("Motorcycle") Engine
or @StringKey("Lorry") Engine
might highlight the kind of configuration for which Dagger is more practical. Furthermore, bindings as simple as yours could also be expressed using a @Binds
annotation (though the way you expressed it is fine for now).