e: C:\gradle\build\DaggerKotlin\app\tmp\kapt3\stubs\debug\net\xpece\test\daggerkotlin\TheComponent.java:8: error: [Dagger/MissingBinding] java.util.Map<kotlin.reflect.KClass<? extends androidx.lifecycle.ViewModel>,javax.inject.Provider<androidx.lifecycle.ViewModel>> cannot be provided without an @Provides-annotated method.
public abstract interface TheComponent {
^
java.util.Map<kotlin.reflect.KClass<? extends androidx.lifecycle.ViewModel>,javax.inject.Provider<androidx.lifecycle.ViewModel>> is injected at
net.xpece.test.daggerkotlin.DaggerViewModelFactory(creators)
net.xpece.test.daggerkotlin.DaggerViewModelFactory is injected at
net.xpece.test.daggerkotlin.ViewModelModule.bindViewModelFactory(impl)
androidx.lifecycle.ViewModelProvider.Factory is injected at
net.xpece.test.daggerkotlin.MainActivity.vmf
net.xpece.test.daggerkotlin.MainActivity is injected at
net.xpece.test.daggerkotlin.TheComponent.inject(net.xpece.test.daggerkotlin.MainActivity)
Injecting a Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>> based on KClass<out ViewModel keys produces an error.
Changing to Map<KClass ... doesn't help.
Injecting a Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>> based on KClass<out ViewModel keys should work as before.
Migrate the class key annotation to Java.
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
@Retention(AnnotationRetention.RUNTIME)
@MapKey
annotation class ViewModelKey(val value: KClass<out ViewModel>)
@Singleton
class DaggerViewModelFactory @Inject constructor(
private val creators: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>
) : ViewModelProvider.Factory {
// ...
}
@Module
abstract class ViewModelModule {
@Binds
abstract fun bindViewModelFactory(impl: DaggerViewModelFactory): ViewModelProvider.Factory
@Binds
@IntoMap
@ViewModelKey(ViewModelOne::class)
abstract fun bindViewModelOne(impl: ViewModelOne): ViewModel
@Binds
@IntoMap
@ViewModelKey(ViewModelTwo::class)
abstract fun bindViewModelTwo(impl: ViewModelTwo): ViewModel
}
@Component(modules = [ViewModelModule::class])
@Singleton
interface TheComponent {
fun inject(activity: MainActivity)
}
class MainActivity : Activity() {
protected val component by lazy {
DaggerTheComponent.create()
}
@Inject
protected lateinit var vmf: ViewModelProvider.Factory
protected val vm1: ViewModelOne by lazy { vmf.create(ViewModelOne::class.java) }
protected val vm2: ViewModelTwo by lazy { vmf.create(ViewModelTwo::class.java) }
override fun onCreate(savedInstanceState: Bundle?) {
component.inject(this)
super.onCreate(savedInstanceState)
}
}
The issue probably comes from Kotlin as it is the Kotlin update that stopped the code for working.
I made a Kotlin issue just in case : https://youtrack.jetbrains.com/issue/KT-30979 (I was working on my own sample then saw your issue)
Would you mind expanding on the workaround with an example?
@VeegaP You switch the ViewModelKey from Kotlin to Java
/**
* Workaround in Java due to Dagger/Kotlin not playing well together as of now
* https://github.com/google/dagger/issues/1478
*/
@MapKey
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewModelKey {
Class<? extends ViewModel> value();
}
Thank you @bleeding182 :)
Should be fixed in kotlin 1.3.31 (yet to be released) according to the kotlin issue linked above
I still have the same issue. @bleeding182 Workaround doesn't work for me.
@vladkarpman post your error and your exact workaround code
Setup:
_Dagger version_ = 2.22.1
_Kotlin version_ = 1.3.30
_Gradle plugin version_ = 3.4.0
_Gradle version_ = 5.1.1
I am using workaround which was suggested @bleeding182.
It's simply class which is written on Java instead of Kotlin:
import androidx.lifecycle.ViewModel;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import dagger.MapKey;
@MapKey
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewModelKey {
Class<? extends ViewModel> value();
}
This is my ViewModelFactory:
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import javax.inject.Inject
import javax.inject.Provider
import javax.inject.Singleton
@Singleton
class ViewModelFactory @Inject constructor(
private val viewModels: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>) :
ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return viewModels[modelClass]?.get() as T
}
}
Below is my ViewModelModule (nothing special) :
@Module
abstract class ViewModelModule {
@Binds
abstract fun bindViewModelFactory(viewModelFactory: ViewModelFactory): ViewModelProvider.Factory
@Binds
@IntoMap
@ViewModelKey(DiscoverViewModel::class)
abstract fun bindDiscoveryViewModel(discoverViewModel: DiscoverViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(LoginViewModel::class)
abstract fun bindLoginViewModel(loginViewModel: LoginViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(OnBoardingViewModel::class)
abstract fun bindOnBoardingViewModel(onBoardingViewModel: OnBoardingViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(ProfileViewModel::class)
abstract fun bindProfileViewModel(profileViewModel: ProfileViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(ProfileCityViewModel::class)
abstract fun bindProfileCityViewModel(profileCityViewModel: ProfileCityViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(ProfileDetailViewModel::class)
abstract fun bindProfileDetailViewModel(profileDetailViewModel: ProfileDetailViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(ProfileLanguageViewModel::class)
abstract fun bindProfileLanguageViewModel(profileLanguageViewModel: ProfileLanguageViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(MyQuestViewModel::class)
abstract fun bindMyQuestViewModel(myQuestViewModel: MyQuestViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(TasksViewModel::class)
abstract fun bindTasksViewModel(tasksViewModel: TasksViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(QuestDetailViewModel::class)
abstract fun bindQuestDetailViewModel(questDetailViewModel: QuestDetailViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(QuestFinishViewModel::class)
abstract fun bindQuestFinishViewModel(finishViewModel: QuestFinishViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(QuestsViewModel::class)
abstract fun bindQuestsViewModel(questsViewModel: QuestsViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(MainViewModel::class)
abstract fun bindMainViewModel(mainViewModel: MainViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(BuyPromoCodeViewModel::class)
abstract fun bindBuyPromoCodeViewModel(buyPromoCodeViewModel: BuyPromoCodeViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(FactViewModel::class)
abstract fun bindFactViewModel(factViewModel: FactViewModel): ViewModel
}
And this is error which i am facing:
/Users/vladislavkarpman/StudioProjects/StreetGames/app/build/tmp/kapt3/stubs/debug/com/streetgames/common/di/application/ApplicationComponent.java:8: error: [Dagger/MissingBinding] java.util.Map
,javax.inject.Provider > cannot be provided without an @Provides-annotated method.
@vladkarpman list of things you need to check:
ViewModelKey defined in Kotlin.import java.lang.annotation.*;ViewModelKey.@mikehc i checked everything from provided list, still the same error :(
@vladkarpman post the rest of the other files, including imports. Maybe someone else has a better idea.
@vladkarpman switch back to the old Kotlin version until this gets fixed.
Which imports are you using in the factory class?
@DDihanov added imports inside ViewModelFactory
@vladkarpman Yup everything is fine on your end. I don't know why it keeps crashing. I "fixed" this issue by downgrading to org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.20 and using the Kotlin ViewModelKey class.
@DDihanov something went totally wrong, now if i even downgrade Kotling version, i still have this issue. Before everything just worked. Of course, I tried to clean project.
Maybe it's because of new Android Studio, i am using 3.4...
Sometimes a build cache of kapt doesn't track deleted kotlin files. Probably you have to not only clean build dir but delete build cache as well.
Please try to run ./gradlew cleanBuildCache in your project, then remove your build folder, then try again.
I can confirm, downgrading Kotlin fixes this..
I reset my branch to previous commit and investigated a bit more and found out that cause of my issue was gradle version 5.1.1 in mix with latest Kotlin version.
Once i changed Gradle version to 4.10.1 and plugin version 3.3.2 (BTW, Gradle plugin version 3.4 only works for gradle version 5.1.1), everything started to work, of course, only with version of Kotlin 1.3.21.
So, robust solution to this issue is following:
Will wait for Koltin&Gradle fixes :)
This is now fixed in kotlin 1.3.31 https://github.com/JetBrains/kotlin/blob/1.3.30/ChangeLog.md
I'm having the same issue on
kotlin_version = '1.3.41'
same
I'm having the same issue on
kotlin_version = '1.3.41'
same
same in kotlin 1.3.50
Facing this with 1.3.41 , will check with latest - x.50 and x.60 and see if it resolves
@aldefy Same issue in x.50, x.60 and x.61
what are you guys trying at the moment ?
Do i write the provides func replacing abstract Binds ?
1.3.70 same issue
1.3.71 same 🤔
Still happening with 1.3.71
Dagger 2.72
AGP 4.0-beta04
Gradle 6.1.1
Changing to java doesn't work. Why is this issue closed, it doesn't seem to be resolved yet
To anyone still complaining, care to provide a sample repro project? Thank you.
I can confirm the Java workaround [1] works fine with
Dagger 2.21 && 2.27
Gradle 5.4.1 && 6.1.1 && 6.3
Kotlin 1.3.70 && 1.3.71
[1] https://github.com/google/dagger/issues/1478#issuecomment-485976409
I clear my gradle cache and rerun and the java solution is working now
I tried all of these and none of the above worked for me
dagger_version = ‘2.27'
kotlin_version = ‘1.3.72'
build:gradle:3.6.3'
https://github.com/google/dagger/issues/1540
Adding @JvmSuppressWildcards solved the problem.
private val providers: Map
Tried the solutions provided in this thread, yet facing the same issue.
dagger = 2.15
kotiln version = 1.3.72
build.gradle = 4.0.1
ext.kotlin_version = "1.4.0"
ext.daggerVersion = '2.25.4'
build.gradle = "4.0.1"
Still facing the issue. Anyone found any solution ?
Most helpful comment
The issue probably comes from Kotlin as it is the Kotlin update that stopped the code for working.
I made a Kotlin issue just in case : https://youtrack.jetbrains.com/issue/KT-30979 (I was working on my own sample then saw your issue)