Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I use Dagger 2's field injection in Kotlin?

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?

like image 398
Damn Vegetables Avatar asked Nov 12 '17 11:11

Damn Vegetables


People also ask

Does dagger work with Kotlin?

Dagger is a fully static, compile-time dependency injection framework for Java, Kotlin, and Android. It is an adaptation of an earlier version created by Square and now maintained by Google.

What is dagger 2 Android Kotlin?

What is Dagger2? Dagger2 is a static compile-time dependency injection Framework for Java,Kotlin and Android. It should actually be Dagger, Dagger2 simply implies the second version which was a complete re-write of the DI framework. The earlier version was created by Square. Dagger2 is now maintained by Google.

How do you implement dagger in Kotlin?

They are enabled by adding id 'kotlin-kapt' to the top of the file below the id 'kotlin-android-extensions' line. In the dependencies, the dagger library contains all the annotations you can use in your app and dagger-compiler is the annotation processor that will generate the code for us.


1 Answers

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 

Edit: You don't need to add the field target when using Dagger 2.25 or newer.


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 
like image 136
Eugen Pechanec Avatar answered Sep 29 '22 10:09

Eugen Pechanec