42

I saw the following example on the Dagger 2 website:

class Thermosiphon implements Pump {
  private final Heater heater;

  @Inject
  Thermosiphon(Heater heater) {
    this.heater = heater;
  }

  ...
}

and the documentation:

When a new instance is requested, Dagger will obtain the required parameters values and invoke this constructor.

When I write a Module to provide a Thermosiphon like

@Module
public class ThermosiphonModule {

    @Provides
    @Singleton
    Thermosiphon provideThermosiphon() {
        return new Thermosiphon(???);
    }

}

the Thermosiphon constructor still requires a Heater as an argument, rendering the whole 'automatic injection of constructor dependencies' useless.

I tried

return new Thermosiphon(null); 

and

return new Thermosiphon(); 

(empty constructor) and hoped for Dagger2 to pick up that I wanted the missing Heater to be injected, yet the Heater of the provided Thermosiphon is always null;

I verified though my HeaterComponent / HeaterModule are working fine and are able to provide a Heater.

Do I completey misunderstand the whole feature of 'Dagger satisfies constructor dependencies for you' or am I missing something?

fweigl
  • 21,278
  • 20
  • 114
  • 205
  • Adding this documentation which explains that you do not need to create a provider when an object has `@Inject` annotation to its constructor, which makes sense since Dagger now already know how to create an instance of the object. https://www.vogella.com/tutorials/Dagger/article.html#defining-dependencies-object-consumers – Bitwise DEVS Feb 20 '22 at 19:28

2 Answers2

61

If you're using modules, then if you have two provider modules bound to the same component, then you'll be able to allow them to see the heater as a constructor parameter.

@Module
public class HeaterModule {
    @Provides
    @Singleton
    Heater heater() {
        return new Heater(); // if not using @Inject constructor
    }
}

@Module
public class ThermosiphonModule {
    @Provides
    @Singleton
    Thermosiphon thermosiphon(Heater heater) {
        return new Thermosiphon(heater); // if not using @Inject constructor
    }
}

@Singleton
@Component(modules={ThermosiphonModule.class, HeaterModule.class})
public interface SingletonComponent {
    Thermosiphon thermosiphon();
    Heater heater();

    void inject(Something something);
}

public class CustomApplication extends Application {
    private SingletonComponent singletonComponent;

    @Override
    public void onCreate() {
        super.onCreate();
        this.singletonComponent = DaggerSingletonComponent.builder().build(); //.create();
    }

    public SingletonComponent getSingletonComponent() {
        return singletonComponent;
    }
}

But with constructor injection, you will also be able to provide objects of that given scope, or unscoped objects, as long as they have a @Inject constructor.

For example,

@Singleton
@Component // no modules
public interface SingletonComponent {
    Thermosiphon thermosiphon();
    Heater heater();

    void inject(Something something);
}

And

@Singleton
public class Heater {
    @Inject
    public Heater() {
    }
}

And

@Singleton
public class Thermosiphon {
    private Heater heater;

    @Inject
    public Thermosiphon(Heater heater) {
        this.heater = heater;
    }
}

Or

@Singleton
public class Thermosiphon {
    @Inject
    Heater heater;

    @Inject
    public Thermosiphon() {
    }
}
Community
  • 1
  • 1
EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428
  • @EpicPandaForce excuse me, could you help me on this topic? http://stackoverflow.com/q/43308649/6596724 Thanks – tux-world Apr 09 '17 at 19:12
  • 1
    My question is: are you able to mix those two dependency Injections Rules? `class Usecase @Inject constructor(val restApi: RestService)` and than `class ViewModel{ lateinit var usecase : Usecase init{ Application.getRestComponent().inject(this) } }` – murt Jul 21 '17 at 11:10
  • Answer for my question https://stackoverflow.com/questions/43287645/dagger-2-injecting-constructors – murt Jul 21 '17 at 11:33
  • good help for understanding the alternative way of using constructor injection vs. using module. – lannyf Jan 17 '18 at 15:22
33

For one, since you've annotated the constructor of Thermosiphon with @Inject, you don't need an @Provides method. Dagger uses this constructor to create an instance when needed. Just annotate the Thermosiphon class itself with @Singleton to preserve the singleton behavior.

If you do want to use an @Provides method, and to answer your question fully, you can specify the Heater as a parameter to the method:

@Module
public class ThermosiphonModule {

    @Provides
    @Singleton
    Thermosiphon provideThermosiphon(Heater heater) {
        return new Thermosiphon(heater);
    }

}
nhaarman
  • 98,571
  • 55
  • 246
  • 278
  • Does it mean that you can use Thermosiphon for field injection as well without needing to define a provider? I was confuse when I tried to use a class that annotates its constructor with `@Inject` for field injection and it works without any provider. – Bitwise DEVS Feb 20 '22 at 19:19