I have a simple interface and class:
interface Foo {
fun value(): Int
}
class FooImpl : Foo {
override fun value() = 100
}
Now I want to create a factory for Foo and be able to inject it. I'm trying with following code:
interface FooFactory : () -> Foo
@Module
class AppModule {
// provides FooFactory
@Provides
fun provideFooFactory() = object : FooFactory {
override fun invoke() = FooImpl()
}
// uses FooFactory
@Provides
fun provideFoo(factory: FooFactory) = factory()
}
@Component(modules = [AppModule::class])
interface AppComponent {
fun foo(): Foo
}
And the place where Foo is injected:
@Test
fun test() {
val component = DaggerAppComponent.builder().build()
val foo = component.foo()
Assert.assertEquals(100, foo.value())
}
Works perfect! However, I think, it's a kind of ugly to define FooFactory as an interface so I tried to replace:
interface FooFactory : () -> Foo
with:
typealias FooFactory = () -> Foo
And now I'm getting compile time error:
Error:Gradle:
kotlin.jvm.functions.Function0<? extends net.chmielowski.daggerkotlin.Foo>
cannot be provided without an @Provides-annotated method.
If I understand it correctly, the problem is that typealias is inlined in the process of build (before Dagger code generation) and Dagger has a problem with finding out which provider provides instance for parametrized (generic) type Function0<? extends Foo> .
By the way: if I remove Foo and use just FooImpl everywhere, the problem does not occur. This mean that the problem is not with the generics itself but with the class parametrized by abstract type.
What is the solution to this problem?
To be clear - the rationale behind using typealias instead of interface is to be able to write:
@Provides
fun provideFooFactory() = { FooImpl() }
instead of:
@Provides
fun provideFooFactory() = object : FooFactory {
override fun invoke() = FooImpl()
}
I had a similar issue today where I was using a kotlin lambda to return a value through dagger.
DaggerModule.kt
@Provides
fun provideFoo() = {
foo.get()
}
BarClass.kt
BarClass( private val fooFunction: () -> Foo )
I was getting the same error you were seeing where dagger couldn't find the provided method.
(as above)
kotlin.jvm.functions.Function0<? extends net.chmielowski.daggerkotlin.Foo>
cannot be provided without an @Provides-annotated method.
For me it was not enough to explicitly declare the type in the provider. The solution instead had to do with how kotlin and java deal with generics. Basically when translating that function into Java (which dagger still does under the hood) it was adding < ? extends Foo> to the method signature. You can suppress this behavior with the @JvmSuppressWildcards annotation in the constructor of the receiving class.
BarClass( private val fooFunction: () -> @JvmSuppressWildcards Foo )
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With