Reputation: 11419
I'm trying to follow the sample here
I have already used Dagger2 with the AndroidInjector successfully but now I was experimenting the new DaggerApplication
and DaggerAppCompatActivity
.
I get the error:
Error:(5, 1) error: [dagger.android.AndroidInjector.inject(T)] java.lang.String cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method.
I don't think that the new Dagger classes are causing the issue.
If I remove the @DeviceModel
in BuildModule.kt the code compiles.
Any suggestion?
Here the code:
The AppComponent.kt
@Component(modules = arrayOf(
AndroidSupportInjectionModule::class,
AppModule::class,
MainActivitySubComponent.MainActivityModule::class
))
interface AppComponent : AndroidInjector<App> {
@Component.Builder
abstract class Builder : AndroidInjector.Builder<App>()
}
The AppModule.kt
@Module(subcomponents = arrayOf(MainActivitySubComponent::class))
class AppModule {
}
The BuildModule.kt
@Module
class BuildModule {
@Provides
@DeviceModel
fun provideModel(): String {
return MODEL
}
}
The DeviceModel.kt
@Qualifier
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class DeviceModel
The MainActivitySubComponent.kt
@Subcomponent(modules = arrayOf(BuildModule::class))
interface MainActivitySubComponent : AndroidInjector<MainActivity> {
@Subcomponent.Builder
abstract class Builder : AndroidInjector.Builder<MainActivity>()
@Module(subcomponents = arrayOf(MainActivitySubComponent::class))
abstract class MainActivityModule {
@Binds
@IntoMap
@ActivityKey(MainActivity::class)
internal abstract fun bind(builder: MainActivitySubComponent.Builder): AndroidInjector.Factory<out Activity>
}
}
The *MainActivity.kt**
class MainActivity : DaggerAppCompatActivity() {
@Inject
@DeviceModel
lateinit var model: String
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Log.d(model, model);
}
}
The App.kt
class App : DaggerApplication() {
override fun applicationInjector(): AndroidInjector<App> {
return DaggerAppComponent.builder().create(this)
}
}
Upvotes: 0
Views: 438
Reputation: 312
When using Dagger with Kotlin objects, we have to consider how Kotlin actually creates properties in the JVM.
@Inject
@DeviceModel
lateinit var model: String
With a property like this, Kotlin compiles three Java elements: a private backing field, a getter, and a setter (due to var
rather than val
). With no further clues as to your intent, Kotlin places your DeviceModel
annotation on the getter.
The solution is to specify that the field is to be annotated with @field:[annotation]
.
@Inject
@field:DeviceModel
lateinit var model: String
You may also need to use @JvmField
to make the backing field public for Dagger, which would preclude using lateinit
, and of course, require you to initialize the String.
@Inject
@field:DeviceModel
@JvmField
var model: String
Update: I'm not sure why, but in my testing, the field was private, which is why I suggested @JvmField
. According to the Kotlin documentation, the field should be created with the same visibility as the setter.
Note that in general, Kotlin is smart enough to apply custom annotations with @Target(AnnotationTarget.FIELD)
to the backing field, but this would prevent you from also using it on the fun providesModel
Upvotes: 2