Search code examples
kotlindagger-2

Dagger 2 Modules and generic parameters in Kotlin


The question is if Dager 2 supports proper Generic parameters. I have the following test class:

@Module
class Test {

    @Provides
    fun t(
        l: List<String>,
        l1: List<Number> /* Error points to this dependency */
    ): String {

        return "String" + l + l1
    }

    @Provides
    fun list1(): List<Number>{
        throw Error()
    }

    @Provides
    fun list() : List<String> {
        throw Error()
    }
}

in the AppComponent I have usage

@Component(modules = [Test::class])
interface AppComponent {

    fun str(): String
}

When I try to compile I got the following error:

/AppComponent.java:8: error: [Dagger/MissingBinding] java.util.List<? extends java.lang.Number> cannot be provided without an @Provides-annotated method. public abstract interface AppComponent { ^ java.util.List<? extends java.lang.Number> is injected at com.example.android.dagger.di.Test.t(…, l1) java.lang.String is requested at com.example.android.dagger.di.AppComponent.str()

The question is if Dagger support usage of generic parametered types in modules

UPDATE As per @Jeff_Bowman answer, the convenient way of removing wildcards would be with usage on Kotlin typealias, like this:

typealias NumericList = List<@JvmSupressWildcards Number>

@Module
class Test {

    @Provides
    fun t(
        l: List<String>,
        l1: NumericList 
    ): String {

        return "String" + l + l1
    }

    @Provides
    fun list1(): NumericList{
        throw Error()
    }

    ........

}

Solution

  • java.util.List<? extends java.lang.Number> cannot be provided without an @Provides-annotated method

    Note the wildcard: Kotlin defaults to using wildcards in a way that Java does not. You can adjust those types using the @JvmWildcard and @JvmSuppressWildcards to ensure Dagger sees matching declarations.

    You have your choice of whether the parameter has wildcards suppressed or whether your @Provides return value has wildcards added. The answer may depend on whether you expect most of your call sites to be Java versus Kotlin.

    @Provides
    fun t(
        l: List<String>,
        l1: List<@JvmSuppressWildcards Number>  // Note wildcard suppression
    ): String {
        return "String" + l + l1
    }
    

    See also: