Dagger2 Qualifier not working with Kotlin?

2020-03-13 06:45发布

问题:

I have a simple class as below

class MainString(val msg: String)

I want to inject with different argument to it, so I use the @Named Qualifier as per the guide shown in https://google.github.io/dagger/users-guide

With that my AppModule has

@Provides @Named("Two")
fun provideTwoMainString(): MainString {
    return MainString("Two")
}

@Provides @Named("One")
fun provideOneMainString(): MainString {
    return MainString("One")
}

And in my MainActivity, I just call

@Inject @Named("One")
lateinit var stringOne: MainString

@Inject @Named("Two")
lateinit var stringTwo: MainString

However, when I compile, it complains

Error:(11, 1) error: com.elyeproj.demo_dagger_scope.MainString cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method.

It seems to want me to provide another Provider without the qualifier. So if I add the below, all will compiles. But it is not of used to me, as I want to have different argument injection.

@Provides
fun provideMainString(): MainString {
    return MainString("Solo")
}

What have I done wrong?

回答1:

Annotation work slightly different on kotlin. look this doc

You have to annotate the field as:

@Inject @field:Named("Two")
lateinit var stringOne: MainString


回答2:

If you add the following to your qualifier annotation:

@Target(FIELD, VALUE_PARAMETER, FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER)

then you won't have to add "field:"

For example, with:

  @Qualifier
  @Retention(RUNTIME)
  @Target(FIELD, VALUE_PARAMETER, FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER)
  annotation class One

you can inject as follows:

  @Inject @One lateinit var stringOne: String

Unfortunately @Named doesn't specify the @Target(..), so just create your own annotations. @Named is a bad idea anyway, since it's using string literals.



回答3:

1) If you are using a qualifier like following, here 'OmdbService'

@Qualifier
public annotation class OmdbService

Then use

@Inject  @field:OmdbService lateinit var retrofitOmdbService: Retrofit

2) If are using a named provider like following, here 'orangeservice_retrofit'

@Provides
    @OrangeApplicationScope
    @Named("orangeservice_retrofit")
    fun retrofit(okHttpClient :OkHttpClient, gson : Gson, c :Context): Retrofit {
        return Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create(gson))
                .client(okHttpClient)
                .baseUrl(c.getString(R.string.base_url))
                .build()
}

Then use

@Inject @field:Named("orangeservice_retrofit") lateinit var retrofitOrangeService: Retrofit