Переплет в карту с типом KClass

Я пытаюсь привязать подклассы ViewModel к карте их типами KClass:

@Module abstract class ViewModelModule {

    @Binds @IntoMap @ViewModelKey(MyViewModel::class)
    abstract fun bindsMyViewModel(viewModel: MyViewModel): ViewModel

    @Binds abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory

}

Но я получаю ошибку компилятора Dagger:

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)

Вышеупомянутый ViewModelModule включен в мой AppModule, который является модулем в моем AppComponent. Поэтому кинжал должен иметь возможность Map<KClass<out ViewModel>, Provider<ViewModel>>, требуемый моим ViewModelFactory, но я не могу понять, почему он сбой.


Я также попытался переключить класс аннотации ViewModelKey на Java, взяв Class как параметр конструктора вместо KClass. Затем изменил мой ViewModelFactory, чтобы он зависел от a Map<Class<out ViewModel>, Provider<ViewModel>>, но произошла одна и та же ошибка.

Ответы

Ответ 1

При использовании KClass в аннотации он фактически скомпилируется в Java Class. Но актуальной проблемой является подстановочный знак в java.util.Map<kotlin.reflect.KClass<? extends android.arch.lifecycle.ViewModel>,? extends javax.inject.Provider<android.arch.lifecycle.ViewModel>>, который генерирует компилятор Kotlin.

Предполагая, что @ViewModelKey определяется как

@MapKey
annotation class ViewModelKey(val value: KClass<out ViewModel>)

Вам нужно определить сайт для инъекций как

Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>

Использование @JvmSuppressWildcards не даст компилятору создавать подстановочные знаки.

Я действительно не знаю, почему подстановочные знаки не поддерживаются компилятором Dagger. Вы можете увидеть аналогичную проблему здесь: Кинжал 2: Как ввести карту < Class <? расширяет Foo > , Provider <? → →