Kotlin + Dagger2: cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method
Asked Answered
B

2

8

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
Brower answered 4/1, 2018 at 21:32 Comment(5)
do you have an @Provides @French annotated method in your GreetingsModule?Ackack
oops, I removed that one from the module but left it in the Activity. I updated the post. thanksBrower
@Brower did you try compiling with just the code from the question? Just to make sure the problem is not in the rest of your code.Ackack
@Ackack yes, I tried just with this code, originally it used DaggerAndroid classes. I removed everything and left all manually. I spent already more than 2 trying to make it work.Brower
@Onik The module doesn't depend on anything, anyway I tried and got the same u.uBrower
C
22

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
Checklist answered 4/1, 2018 at 22:37 Comment(4)
It worked like a shine, you are a lifesaver. Thanks for the explanation + docBrower
I spent an hour trying to figure out what's wrong, and this solution saved me, thanks!Enamel
so this is for using Qualifier, what of using named annotations? edit: apparently you can use something like this @field:Named("aaa")Bascule
more concise variant: \@field:[Inject Spanish] instead of \@Inject @field:SpanishVarion
V
0

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
Varion answered 5/10, 2018 at 14:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.