javadagger-2multibinding

Dagger multibinding java - for two or multiple implementation


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
  }

}

Solution

  • 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).