question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Class keys into map don't work in Kotlin 1.3.30

See original GitHub issue

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

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:83
  • Comments:37

github_iconTop GitHub Comments

26reactions
NitroG42commented, Apr 12, 2019

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)

22reactions
bleeding182commented, Apr 19, 2019

@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();
}
Read more comments on GitHub >

github_iconTop Results From Across the Web

Update to Kotlin 1.3.30 breaks build with Dagger 2.21
Tried to disable/enable the kapt options from the article, tried gradle clean, invalidate caches, nothing helps. Only downgrading to 1.3.
Read more >
androidExtensions "parcelize" not work in Kotlin 1.3.30-kotlin
I find the error. Kotlin plugin should be enabled before 'kotlin-android-extensions'. so change the order to apply plugin: 'com.android.application' apply ...
Read more >
What's new in Kotlin 1.4
RUNTIME ). Compile the annotation class declaration to JVM bytecode target version 1.8+. You can specify it with -jvm-target=1.8 compiler ...
Read more >
See what's coming in Kotlin 1.3-M1 - The JetBrains Blog
We are also working on a multiplatform version of the coroutine APIs ... However, the Kotlin 1.3-M1 release does not provide any support...
Read more >
Kotlin Language Documentation
compiled classes to the requirements of the framework. Kotlin applications can be deployed into any host that supports Java Web applications, including.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found