With the recent versions of dagger 2 one of the improvements made are the possibility of having static provide methods. Simply so:
@Provides
static A providesA() {
return A();
}
I was wondering how does one go about doing this in kotlin? I've tried
@Module
class AModule {
companion object {
@JvmStatic
@Provides
fun providesA(): A = A()
}
}
But I get the error message:
@Provides methods can only be present within a @Module or @ProducerModule
I'm guessing there's something going on here with the companion object, however I'm quite new to Kotlin and I'm unsure of how one can do this. Is it even possible?
Thanks!
I can't test it right now, but I think this should work:
@Module
object AModule {
@JvmStatic
@Provides
fun providesA(): A = A()
}
Although I think zsmb13's solution is better, I found another solution which works
@Module
class AModule {
@Module
companion object {
@JvmStatic
@Provides
fun providesA(): A = A()
}
// add other non-static provides here
}
However, note that there will be two generated classes: AModule_ProvidesAFactory
and AModule_Companion_ProvidesAFactory
rather than the one AModule_ProvidesAFactory
class for the case with an object instead of a class with a companion object
A great explanation which seems to be Google-approved is at https://github.com/google/dagger/issues/900
Specifically, see:
Static provides can be achieved via @JvmStatic. There are two scenarios I see this come up:
top-level object
s
@Module object DataModule {
@JvmStatic @Provides fun
provideDiskCache() = DiskCache()
}
If you have an existing class
module, things get a bit weirder
@Module abstract class DataModule {
@Binds abstract fun provideCache(diskCache: DiskCache): Cache
@Module
companion object {
@JvmStatic @Provides fun provideDiskCache() = DiskCache()
}
}
The way this works is as follows:
the companion object must also be annotated as @Module under the hood,
the kotlin compiler will duplicate those static provides methods into
the DataModule class. Dagger will see those and treat them like
regular static fields. Dagger will also see them in the companion
object, but that "module" will get code gen from dagger but be marked
as "unused". The IDE will mark this as such, as the provideDiskCache
method will be marked as unused. You can tell IntelliJ to ignore this
for annotations annotated with @Provides via quickfix
For the static only approach, I like the solution of zsmb13.
However, I came here because I wanted to combine @Provides
and @Binds
within one module.
This is not directly possible but with two nested modules (as Omar Al Halabi pointed out).
I took a slightly different approach for combining @Provides
and @Binds
:
@Module(includes = [MyModule.Bindings::class])
object MyModule {
@Module
interface Bindings {
@Binds
fun bindA(a: AImpl): A
}
@Provides
@JvmStatic
fun provideB(): B = BImpl()
}
The differences are:
- The outer module is an object providing the static functions. This spares using the unintentional
companion object
.
- The inner module holds the abstract bindings. I can use an interface here, which spares the
abstract
modifier in both the class and the function.
- The outer module includes the inner module so I don't have to include the inner module elsewhere.