I posted a question (Dagger 2 does not generate the component class (Android, Kotlin)), and after some experiments, it seems that the problem might be due to that Kotlin hides the field.
class CoffeeShop {
@Inject
var theCoffee: Coffee? = null
}
The error message is,
:app:kaptDebugKotline: ...\CoffeeShop.java:7:
error: Dagger does not support injection into private fields
e: private ....Coffee theCoffee;
theCoffee
was not private in my source code. But I think Kotlin may be translating
class CoffeeShop {
@Inject
var theCoffee: Coffee? = null
}
into Java code of
class CoffeeShop {
@Inject
private Coffee theCoffee = null;
public Coffee getTheCoffee();
public void setTheCoffee();
}
Can I use field injection in Kotlin?
I think Kotlin may be translating [...] into Java code of [...]
And you would be correct, that's exactly what happens.
Typically in Kotlin you wouldn't write
@Inject var coffee: Coffee? = null
because when you're going to access coffee, it will never be null. In other words you will always inject the object before accessing it's fields. That makes the operators !!
redundant and ?
unnecessary. Kotlin has lateinit
property modifier to express this.
@Inject lateinit var coffee: Coffee
When you use lateinit
the generated field has the same visibility as its getter and setter, in this case public
. This makes it work with Dagger.
You can see the result by viewing generated Kotlin bytecode.
Main menu > Tools > Kotlin > Show Kotlin Bytecode
However, even better approach would be injecting the class constructor:
class CoffeeShop @Inject constructor(val coffee: Coffee) {
//...
}
In this case coffee
is not var
and can't be reassigned.
Injecting constructor is not an option when the instance is created for you by a framework, Android activity is a good example.
Note: When using qualifiers you have to specify field
annotation target on them:
@Inject @field:Named("Arabica") @field:Arabica
lateinit var coffee: Coffee
Can I use field injection in Kotlin?
Yes you can. As explained above, field injection is actually applied for lateinit
properties.
But you were probably interested in generating and injecting fields without getter/setter in Kotlin.
@JvmField @Inject
var coffee: Coffee? = null