dagger: Class keys into map don't work in Kotlin 1.3.30

Setup:

  • AGP 3.3.x
  • Dagger 2.21+
  • Kotlin 1.3.30
  • Gradle 5.3.1

Error:

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)

Current state:

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.

Expected state:

Injecting a Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>> based on KClass<out ViewModel keys should work as before.

Workaround:

Migrate the class key annotation to Java.

Relevant code:

@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)
    }
}

Sample

DaggerKotlin.zip

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 83
  • Comments: 37

Commits related to this issue

Most upvoted comments

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)

@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();
}

I’m having the same issue on

kotlin_version = '1.3.41'

I still have the same issue. @bleeding182 Workaround doesn’t work for me.

1.3.71 same 🤔

Should be fixed in kotlin 1.3.31 (yet to be released) according to the kotlin issue linked above

I clear my gradle cache and rerun and the java solution is working now

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

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

@aldefy Same issue in x.50, x.60 and x.61

same in kotlin 1.3.50

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.

@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.