Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dagger 2 - two provides method that provide same interface

lets say I have:

public interface Shape  {}   public class Rectangle implements Shape {  }  public class Circle implements Shape {  } 

and I have a ApplicationModule which needs to provides instances for both Rec and Circle:

@Module public class ApplicationModule {     private Shape rec;     private Shape circle;      public ApplicationModule() {         rec = new Rectangle();         circle= new Circle ();     }      @Provides     public Shape provideRectangle() {         return rec ;     }      @Provides     public Shape provideCircle() {         return circle;     } } 

and ApplicationComponent:

@Component(modules = ApplicationModule.class) public interface ApplicationComponent {     Shape provideRectangle(); } 

with the code the way it is - it won't compile. error saying

Error:(33, 20) error: Shape is bound multiple times.

It makes sense to me that this can't be done, because the component is trying to find a Shape instance, and it finds two of them, so it doesn't know which one to return.

My question is - how can I handle this issue?

like image 912
Ofek Agmon Avatar asked Oct 10 '16 08:10

Ofek Agmon


People also ask

Is dagger 2 deprecated?

It's officially deprecated and you can pretty much ignore it. Google's framework, which became dominant in Android ecosystem, was originally called Dagger 2. Sometimes we still refer to it as such, but, in most cases, we simply call it Dagger today.

What does @inject do dagger?

You use the @Inject annotation to define a dependency. If you annotate a constructor with @Inject , Dagger 2 can also use an instance of this object to fulfill dependencies. This was done to avoid the definition of lots of @Provides methods for these objects.

What is the benefit of dagger?

Benefits of using Dagger Dagger frees you from writing tedious and error-prone boilerplate code by: Generating the AppContainer code (application graph) that you manually implemented in the manual DI section. Creating factories for the classes available in the application graph.


2 Answers

I recently post the answer to a question like this in this post :

Dagger 2 : error while getting a multiple instances of same object with @Named

You need to use @Named("someName")in your module like this:

@Module public class ApplicationModule { private Shape rec; private Shape circle;  public ApplicationModule() {     rec = new Rectangle();     circle= new Circle (); }  @Provides  @Named("rect") public Shape provideRectangle() {     return rec ; }  @Provides  @Named("circle") public Shape provideCircle() {     return circle; } 

}

Then wherever you need to inject them just write

@Inject @Named("rect")  Shape objRect; 

its funny but you have to inject in a different way in Kotlin:

@field:[Inject Named("rect")] lateinit var objRect: Shape 
like image 89
Amir Ziarati Avatar answered Oct 25 '22 16:10

Amir Ziarati


@Qualifier annotations are the right way to distinguish different instances or injection requests that have the same type. The main User's Guide page has a whole section on them.

@Qualifier @Retention(RUNTIME) public interface Parallelogram {} /* name is up to you */  // In your Module: @Provides @Parallelogram public Shape provideRectangle() {     return rec ; }  // In your other injected types: @Inject @Parallelogram Shape parallelogramShape; // or @Inject @Parallelogram Provider<Shape> parallelogramShapeProvider;  // In your Component: @Parallelogram Shape provideRectangle(); 

Aside: Though I agree with sector11 that you shouldn't use new in injected types, Modules are exactly the correct place to call new if needed. Aside from adding the qualifier annotations, I'd say your Module looks just right to me.


EDIT regarding the use of @Named compared to custom qualifier annotations:

  • @Named is a built-in @Qualifier annotation, much like the one I've created above. For simple cases, it works great, but because the binding is just a string you won't get as much help from your IDE in detecting valid keys or autocompleting the key.
  • Like with Named's string parameter, custom qualifiers can have string, primitive, enum, or class literal properties. For enums, IDEs can often autocomplete valid values.
  • @Named and custom qualifiers can be accessed from annotations in exactly the same way by specifying the annotation on the component method, as I've done with @Parallelogram above.
like image 41
Jeff Bowman Avatar answered Oct 25 '22 17:10

Jeff Bowman