2
votes

I was trying my hand learning dagger 2, tried to convert the basic java example into kotlin but unable to do so because of the following error I am getting...

error: Dagger does not support injection into private fields private com.example.Engine engine;

Here is the Java code which is working fine,

public class Car {

    private Engine engine;
    private Wheel wheel;

    @Inject
    public Car(Engine engine, Wheel wheel) {
        this.engine = engine;
        this.wheel = wheel;
    }
}

Car.java class with having 2 dependency.

public class Engine {
    @Inject
    Engine(){}
}

public class Wheel {
    @Inject
    Wheel(){}
}

Here is my kotlin code :-

class Car(@Inject  var engine: Engine, @Inject  val wheels: Wheels) {
    fun drive(){
        Log.d("CAR","<<<<<< DRIVING >>>>>")
    }
}

class Engine @Inject constructor() {}

class Wheels @Inject constructor() {}

@Component
interface CarComponent {
    fun getCar() : Car
}

This is the generated code

public final class Car {
    @org.jetbrains.annotations.NotNull()
    @javax.inject.Inject()
    private com.toi.roboelectric.Engine engine;
    @org.jetbrains.annotations.NotNull()
    @javax.inject.Inject()
    private final com.toi.roboelectric.Wheels wheels = null;

    public final void drive() {
    }

    @org.jetbrains.annotations.NotNull()
    public final com.toi.roboelectric.Engine getEngine() {
        return null;
    }

    public final void setEngine(@org.jetbrains.annotations.NotNull()
    com.toi.roboelectric.Engine p0) {
    }

    @org.jetbrains.annotations.NotNull()
    public final com.toi.roboelectric.Wheels getWheels() {
        return null;
    }

    public Car(@org.jetbrains.annotations.NotNull()
    com.toi.roboelectric.Engine engine, @org.jetbrains.annotations.NotNull()
    com.toi.roboelectric.Wheels wheels) {
        super();
    }
}
2

2 Answers

1
votes

Please update Car Class as

class Car @Inject constructor(var engine: Engine,val wheels: Wheels) {
fun drive(){
    Log.d("CAR","<<<<<< DRIVING >>>>>")
}
0
votes

This issue is about how to inject data into an object in Dagger 2.There are two methods to do it in Dagger 2. One is injecting via class's constructor, another is injecting the class's fields directly.

In your Java implementation, what you injected is the variables in the constructor function's declaration, but not car object's attributes. The injection procedure is nothing about your class's attribute. You set the class's attributes by using the data injected. No matter the attributes are private or public, the setting procedure alway can be done since you are working in the inner side of the class object.

While when defining the Kotlin class as:

class Car(@Inject  var engine: Engine, @Inject  val wheels: Wheels)

If we check the java code of this Kotlin implementation, we can see this time the constructor did nothing except super()

public Car(@org.jetbrains.annotations.NotNull()
com.toi.roboelectric.Engine engine, @org.jetbrains.annotations.NotNull()
com.toi.roboelectric.Wheels wheels) {
    super();
}

This time, the injection procedure is a field direct injection procedure. In this case, Dagger will generate injector class MembersInjector to inject the engine and wheel. To enable the injector class to set the attribute, the attribute must be public. The MembersInjector will be like as below:

public final class Car_MembersInjector implements MembersInjector<Car> {
private final Provider<Engine> engineProvider;
private final Provider<Wheel> wheelProvider;

public Car_MembersInjector(Provider<Engine> engineProvider, Provider<Wheel> wheelProvider) {
    this.engineProvider = engineProvider;
    this.wheelProvider = wheelProvider;
}

public static MembersInjector<Car> create(Provider<Engine> engineProvider,
                                          Provider<Wheel> wheelProvider) {
    return new Car_MembersInjector(engineProvider, wheelProvider);
}

@InjectedFieldSignature("com.freddie.daggerkotlin.Car.engine")
public static void injectEngine(Car instance, Engine engine) {
    instance.engine = engine;
}

@InjectedFieldSignature("com.freddie.daggerkotlin.Car.wheel")
public static void injectWheel(Car instance, Wheel wheel) {
    instance.wheel = wheel;
}

@Override
public void injectMembers(Car instance) {
    injectEngine(instance, engineProvider.get());
    injectWheel(instance, wheelProvider.get());
}
}

There are two solutions to this problem:

1.Constructor Injection. Define Kotlin class as:

class Car @Inject constructor(var engine: Engine, var wheel: Wheel)

or

class Car @Inject constructor(var engine: Engine, var wheel: Wheel)

2.Field Injection. Define Kotlin class as:

class Car @Inject constructor()
{
    @Inject lateinit var engine: Engine
    @Inject lateinit var wheel: Wheel
}

If hope engine and wheel is private, Just and private modifier:

class Car @Inject constructor ()
{
    private lateinit var engine: Engine
    private lateinit var wheel: Wheel
}