I am trying to bind subclasses of ViewModel into a map by their KClass types:
@Module abstract class ViewModelModule {
@Binds @IntoMap @ViewModelKey(MyViewModel::class)
abstract fun bindsMyViewModel(viewModel: MyViewModel): ViewModel
@Binds abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory
}
But I am getting Dagger compiler error:
e: ~/Example/app/build/tmp/kapt3/stubs/debug/com/example/app/injection/AppComponent.java:5: error: [dagger.android.AndroidInjector.inject(T)] java.util.Map<kotlin.reflect.KClass<? extends android.arch.lifecycle.ViewModel>,? extends javax.inject.Provider<android.arch.lifecycle.ViewModel>> cannot be provided without an @Provides-annotated method.
e:
e: public abstract interface AppComponent {
e: ^
e: java.util.Map<kotlin.reflect.KClass<? extends android.arch.lifecycle.ViewModel>,? extends javax.inject.Provider<android.arch.lifecycle.ViewModel>> is injected at
e: com.example.app.ui.ViewModelFactory.<init>(creators)
e: com.example.app.ui.ViewModelFactory is injected at
e: com.example.app.injection.ViewModelModule.bindViewModelFactory(p0)
e: android.arch.lifecycle.ViewModelProvider.Factory is injected at
e: com.example.app.ui.MyFragment.setViewModelFactory(p0)
e: com.example.app.ui.MyFragment is injected at
e: dagger.android.AndroidInjector.inject(arg0)
The above ViewModelModule is included in my AppModule, which is a module in my AppComponent. So Dagger should be able to provide the Map<KClass<out ViewModel>, Provider<ViewModel>> required by my ViewModelFactory, but I cannot figure out why it is crashing.
I also tried switching the ViewModelKey annotation class over to Java, taking a Class as a constructor parameter instead of a KClass. Then modified my ViewModelFactory to depend on a Map<Class<out ViewModel>, Provider<ViewModel>>, but the same error occurred.
When using KClass in an annotation, it actually gets compiled to Java's Class. But the actual issue is the wildcard in java.util.Map<kotlin.reflect.KClass<? extends android.arch.lifecycle.ViewModel>,? extends javax.inject.Provider<android.arch.lifecycle.ViewModel>> that the Kotlin compiler is generating.
Assuming that @ViewModelKey is defined as
@MapKey
annotation class ViewModelKey(val value: KClass<out ViewModel>)
You'll need to define your injection site as
Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>
Using @JvmSuppressWildcards will prevent the compiler from generating wildcards.
I don't actually know, why wildcards are not supported by the Dagger compiler. You can see a similar issue here: Dagger 2: How to inject Map<Class<? extends Foo>, Provider<? extends Foo>>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With