Search code examples
androiddagger-2

Dagger 2: Missing Provider when both parent and child have same inject singnature?


I'm using Dagger 2.24. When I compile the below

fun main() {
    val myClass = MyClass()
}

class MyClass {
    @Inject
    lateinit var stringMe: String

    init {
        DaggerMyComponent.create().subComponent().inject(this)
        println(stringMe)
    }
}

@Component
interface MyComponent {
    fun subComponent(): MySubcomponent
    fun inject(a: MyClass)
}

@Subcomponent(modules = [MeSubModule::class])
interface MySubcomponent {
    fun inject(a: MyClass)
}

@Module
class MeSubModule {
    @Provides
    fun stringMe(): String = "Hi here"
}

It error out stating

error: [Dagger/MissingBinding] java.lang.String cannot be provided without an @Inject constructor or an @Provides-annotated method.
public abstract interface MyComponent {
                ^
  A binding with matching key exists in component: com.elyeproj.modular1bottombase.MySubcomponent
      java.lang.String is injected at
          com.elyeproj.modular1bottombase.MyClass.stringMe
      com.elyeproj.modular1bottombase.MyClass is injected at
          com.elyeproj.modular1bottombase.MyComponent.inject(com.elyeproj.modular1bottombase.MyClass)   

Then I comment out the simple line below, all compile fine.

fun main() {
    val myClass = MyClass()
}

class MyClass {
    @Inject
    lateinit var stringMe: String

    init {
        DaggerMyComponent.create().subComponent().inject(this)
        println(stringMe)
    }
}

@Component
interface MyComponent {
    fun subComponent(): MySubcomponent
//    fun inject(a: MyClass)  // Comment this out.
}

@Subcomponent(modules = [MeSubModule::class])
interface MySubcomponent {
    fun inject(a: MyClass)
}

@Module
class MeSubModule {
    @Provides
    fun stringMe(): String = "Hi here"
}

Suspect it's a Dagger 2 bug, but just write here in case I miss anything?


Solution

  • Apparently, as long as we have inject(a: MyClass) in MyComponent as below, at compile time, it will try to verify that MyComponent are able to satisfied all the @Inject dependencies that MyClass need.

    @Component
    interface MyComponent {
        fun subComponent(): MySubcomponent
        fun inject(a: MyClass)  // Comment this out.
    }
    

    In my case above, MyClass needs String, but MyComponent itself doesn't have the capability to provide the String. So it fails. The current annotation compilation does the check, and doesn't matter if there's actually wired up or not.