Home » Android » android – Kotlin + Dagger2: cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method

android – Kotlin + Dagger2: cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method

Posted by: admin June 15, 2020 Leave a comment

Questions:

I’m getting the following error:

Error:(8, 1) error: java.lang.String cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method.

I’m stuck trying to make a module that provides two qualified Strings. Here is the simplified setup of dagger.

@Singleton
@Component(modules = [GreetingsModule::class])
interface AppComponent {
    fun inject(activity: MainActivity)
}

@Qualifier annotation class Spanish
@Qualifier annotation class French
@Qualifier annotation class English

@Module
@Singleton
class GreetingsModule {

    @Provides
    @Spanish
    fun providesHola(): String = "Hola mundo! - From Dagger"

    @Provides
    @English
    fun providesHello(): String = "Hello world! - From Dagger"

}

The injection is done in MainActivity as:

class MainActivity : AppCompatActivity() {

    @Inject @Spanish
    lateinit var holaMundoText: String

    @Inject @English
    lateinit var helloWorldText: String

}

I also tried declaring the getters directly in the component, but it failed with the same error. Same when declaring the module methods as static.

Just as should be, the code works fine with only one @Provide, then the string is injected in both fields. I assume the problem is with the qualifier.

Any help is highly appreciated.


Using:

  • Android Studio 3.0.1
  • Kotlin 1.2.10
  • Dagger 2.14.1
How to&Answers:

There is a bit of a gotcha with qualified and named injection with JSR-330 + Kotlin (Dagger2 is an implementation of this). From recently reviewing the backlog on the Dagger2 project on Github I know the Google team are looking to provide more proactive assistance/more helpful error messages within a forthcoming release (no timescales).

What you are missing is the @field:<Qualifier> annotation use-type targets as described in the linked documentation. So try;

@Inject @field:Spanish lateinit var holaMundoText: String

Answer:

I think the issue is in Kotlin Compiler, it doesn’t know place where put such annotation (param, setter, field and so on). To avoid ugly @field:Spanish (Spanish annotation class is tagged with Qualifier annotation) I’ve found another solution: Just tag Spanish annotation with Target annotation with appropriate params, see example:

@Qualifier
@Target(FUNCTION, CONSTRUCTOR, FIELD, VALUE_PARAMETER, PROPERTY_SETTER)
annotation class Spanish

then you can use:

@Inject @Spanish
lateinit var holaMundoText: String