I am trying field injection with dagger although constructor injection is working absolutely fine but i don't know what is wrong with field injection. May be I am doing wrong. I am adding the code snippets. I am getting null pointer exception on engine.start() because the engine dependency is not fed. It is similar to A->B->C dependencies where A->B is fed but B->C is not. Its been long I am unable to resolve.
package com.raghav.java.car;
import javax.inject.Inject;
public class App
{
@Inject
Car car;
App() {
DaggerCarComponent.create().inject(this);
}
public static void main( String[] args )
{
App app = new App();
app.perform();
}
private void perform() {
car.run();
}
}
public interface Engine {
void start();
}
class FordEngine implements Engine {
public void start() {
System.out.println("Engine started -- Vroom Vroom");
}
}
public interface Car {
void run();
}
class MarutiCar implements Car {
@Inject
Engine engine;
public void run() {
engine.start();
System.out.println("WOW!! Maruti Running ");
}
}
@Singleton
@Component(modules = {CarModule.class})
public interface CarComponent {
void inject(App app);
}
@Module
class CarModule {
@Singleton
@Provides
public Car provideCar() {
return new MarutiCar();
}
@Singleton
@Provides
public Engine provideEngine() {
return new FordEngine();
}
}
if you want to do nested injection you need to use constructor injection otherwise that wont happen automatically because when you provide a dependency out of Dagger style (through constructor injection or argument injection in module) dagger has no idea about that. change your classes like below:
change your MarutiCar
like this:
class MarutiCar implements Car {
Engine engine;
@Inject
public MarutiCar(Engine engine)
{
this.engine = engine;
}
public void run() {
engine.start();
System.out.println("WOW!! Maruti Running ");
}
}
and your FordEngine
class like this:
class FordEngine implements Engine {
@inject
public FordEngine()
{
}
public void start() {
System.out.println("Engine started -- Vroom Vroom");
}
}
then change your CarModule
like below:
@Module
class CarModule {
@Singleton
@Provides
public Car provideCar(MarutiCar marutiCar) {
return marutiCar;
}
@Singleton
@Provides
public Engine provideEngine(FordEngine fordEngine) {
return fordEngine;
}
}
UPDATE: DAGGER WONT INJECT FIELDS OF A CLASS THAT IS NOT CREATED BY ITSELF.
you are creating the MarutiCar instance by your self how you expect dagger to know what it needs ? you can start a new chain of dagger creation in that class to achieve this which is a weird thing to do.
you need to tell dagger what you need by showing dependencies through constructor or module method argument so that dagger instantiate them for you to know what they need. dagger doesnt provide your nested dependencies injected fields because it hasnt created them so it has no idea about their dependencies, unless you start another chain of dagger creation like what you did in your App
class.
there is another way if you dont want to use constructor injection which i only show this for you Car and MarutiCar
class:
@Module
class CarModule {
@Singleton
@Provides
public Car provideCar(Engine engine) {
MarutiCar marutiCar = new MarutiCar(engine);
}
@Singleton
@Provides
public Engine provideEngine(FordEngine fordEngine) {
return fordEngine;
}
}
and the MarutiCar class would be like this (no need for @inject)
class MarutiCar implements Car {
Engine engine;
public MarutiCar(Engine engine)
{
this.engine = engine;
}
public void run() {
engine.start();
System.out.println("WOW!! Maruti Running ");
}
}