Reputation: 441
After spending a ludicrous amount of time trying to figure out why my dagger injections weren't working; I realised that the "object" type in Kotlin was the problem.
The following did not work, the injected "property" was null.
object SomeSingleton {
@Inject
lateinit var property: Property
init {
DaggerGraphController.inject(this)
}
}
However, the following DID work just fine:
class NotSingleton {
@Inject
lateinit var property: Property
init {
DaggerGraphController.inject(this)
}
}
I tried google, I tried the documentation but I could not pin point the reason behind this. Also note that I havent tried this with JAVA, JAVA doesnt have the concept of singletons built in anyway.
Why is this the case? Why is a kotlin singleton unable to inject members but a regular non-singleton class can?
Upvotes: 42
Views: 21533
Reputation: 3594
This was previously allowed by a bug in Dagger. As others described, it is because the properties in a kotlin object are backed by static fields.
See https://github.com/google/dagger/issues/1665 for the fix. It was fixed in 2.27.
Upvotes: 1
Reputation: 463
A workaround for this can be to extend a BaseClass that consists of the fields to be injected.
object SomeSingleton : BaseClass {
...
...
}
open class BaseClass{
@Inject
lateinit var property: Property
init{
YourDaggerComponent.inject(this)
}
}
This does work, although this would leak this
, which comes up as an android studio warning, to get rid of that make the Base class abstract and instead inject the fields in your original object class
object SomeSingleton : BaseClass {
...
...
// Add the init block here instead of the base class
init{
YourDaggerComponent.inject(this)
}
}
abstract class BaseClass{
@Inject
lateinit var property: Property
//Remove the init block from here
}
And you Dagger AppComponent interface can be like, any of those function def should work
interface Component{
fun inject(someSingleton : SomeSingleton)
//OR
fun inject(baseClass: BaseClass)
}
I hope this helps....
Upvotes: 14
Reputation: 4370
You may still need the @Singleton
decorator on top of your object definition. That decorator doesn't make your class 'singleton', it's just used by Dagger to get all the dependencies in the same spot.
Upvotes: 0
Reputation: 1851
I tried to use dagger.Lazy<YourClass>
and it works
@set:Inject
lateinit var authClient: dagger.Lazy<PlatformAuthClient>
Upvotes: 7
Reputation: 7926
If you look into kotlin bytecode you'll find that the code you've written is translated into following:
public final class SomeSingleton {
public static LProperty; property // <- Notice static field here
public final getProperty()LProperty
...
public final setProperty(LProperty)V
...
}
As you can see the actual field is static which makes it uneligible for instance injection. You may try to move @Inject
annotation onto setter method by doing so:
object SomeSingleton {
@set:Inject
lateinit var property: Property
...
}
Upvotes: 17