Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dagger2 custom @Qualifier usage

Tags:

java

dagger-2

Suppose I'm building a car and I have several Brake beans with different implementations

class Car {
    @Inject
    Car(@BrakeType(value="abs")Brake frontBrake, @BrakeType(value="nonabs")Brake rearBrake) { }
}

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface BrakeType {
    String value();
}

interface Brake {}

@BrakeType(value="abs")
class AbsBrakeImpl implements Brake {
    @Inject AbsBrakeImpl() {}
}

@BrakeType(value="nonabs")
class BrakeImpl implements Brake {
    @Inject BrakeImpl() {}
}

why does my CarModule have to define @Provides for the specific Brake types? Shouldn't the custom annotation type @BrakeType be enough to determine which impl to inject? Or would that require using reflection, which dagger2 does not use?

@Module
public class CarModule {
    @Provides @BrakeType("abs")
    public Brake absBrake() {
        return new AbsBrakeImpl();
    }
    @Provides @BrakeType("nonabs")
    public Brake nonabsBrake() {
        return new BrakeImpl();
    }
}
like image 487
Roger H. Avatar asked Mar 06 '16 16:03

Roger H.


2 Answers

Dagger doesn't look at qualifier annotations on classes, only on @Provides or @Binds methods. So the @BrakeType(value="abs") annotations on your classes don't have any effect.

A more canonical way of writing your code is:

class AbsBrakeImpl implements Brake {
    @Inject AbsBrakeImpl() {}
}

class BrakeImpl implements Brake {
    @Inject BrakeImpl() {}
}

@Module
abstract class CarModule {
    @Binds @BrakeType("abs")
    abstract Brake absBrake(AbsBrakeImpl impl);

    @Binds @BrakeType("nonabs")
    abstract Brake nonabsBrake(BrakeImpl impl);
}

Note that since you have @Inject on the constructors of your implementations, you can simply use Dagger's @Bind to bind the implementations directly to the appropriately qualified interface.

like image 86
Jesse Beder Avatar answered Oct 17 '22 07:10

Jesse Beder


Reflection is probably not a big issue here because it would happen at compile time.

I did not look through the source code, but dagger is but an annotation processor—it registers to be called whenever a set of given annotations is used. While the qualifier alone would probably be enough to find out what you intended, I can think of the following reasons why this could not be the best solution.

javax.inject.Qualifier is part of a bigger API, and might also be used by other libraries in different context. So you might not want dagger to generate code for a method, just because it is annotated with a qualifier.

Another reason could be that since there is the possibility to create custom qualifiers, dagger would have to check every annotation on every method in every module and then in turn determine whether that annotation itself is annotated with @Qualifier to see if the method is of some interest to it. This is rather an unnecessary overhead.

There might be more reasons, but those 2 listed here seem enough to just make users of dagger use some sort of contract: @Provides.

Annotations don't affect the performance of the code, and having an addtional annotation won't do any harm, so there is more to gain than to lose by handling it the way they do.

like image 1
David Medenjak Avatar answered Oct 17 '22 08:10

David Medenjak