@Singleton

Put @Singleton on beans that we want dependency injection on. These are beans that are created ("wired") by dependency injection and put into the context. They are then available to be injected into other beans.

@Inject

Put @Inject on the constructor that should be used for constructor dependency injection. Note that if there is only one constructor we don't need to put the @Inject on it.

If we want to use field injection put the @Inject on the field. Note that the field must not be private and must not be final for field injection.

Constructor injection

@Singleton
public class CoffeeMaker {

  private final Pump pump;

  private final Grinder grinder;

  @Inject
  public CoffeeMaker(Pump pump, Grinder grinder) {
    this.pump = pump;
    this.grinder = grinder;
  }
  ...

The above CoffeeMaker is using constructor injection. Both a Pump and Ginder will be injected into the constructor when the DI creates (or "wires") the CoffeeMaker.

Note that if there is only 1 constructor it is used for dependency injection and we don't need to specify @Inject.

Kotlin constructor

With Kotlin we frequently will not specify @Inject with only one constructor. The CoffeeMaker constructor injection then looks like:

@Singleton
class CoffeeMaker(private val pump: Pump , private val grinder: Grinder)  {

  fun makeCoffee() {
    ...
  }
}

Field injection

@Singleton
public class CoffeeMaker {

  @Inject
  Pump pump;

  @Inject
  Grinder grinder;
  ...

With field injection the @Inject is placed on the field and the field must not be private and it must not be final.

Kotlin field injection

For Kotlin we can consider using lateinit on the property.

@Singleton
class Grinder {

  @Inject
  lateinit var pump: Pump

  fun grind(): String {
    ...
  }
}

Mixed constructor and field injection

We are allowed to mix constructor and field injection. In the below example the Grinder is injected into the constructor and the Pump is injected by field injection.

@Singleton
public class CoffeeMaker {

  @Inject
  Pump pump;

  private final Grinder grinder;

  public CoffeeMaker(Grinder grinder) {
    this.grinder = grinder;
  }

Optional

We can use java.util.Optional to inject dependencies that might not exist (might not be provided).

@Singleton
class Pump {

  private final Heater heater;

  private final Optional<Widget> widget;

  @Inject
  Pump(Heater heater, Optional<Widget> widget) {
    this.heater = heater;
    this.widget = widget;
  }

  public void pump() {
    if (widget.isPresent()) {
      widget.get().doStuff();
    }
    ...
  }
}

List

We can inject a java.util.List of beans that implement an interface.

@Singleton
public class CombinedBars {

  private final List<Bar> bars;

  @Inject
  public CombinedBars(List<Bar> bars) {
    this.bars = bars;
  }

Provider

A Singleton bean can implement javax.inject.Provider to create a bean to be used in injection.

This is more limited than using @Factory and @Bean. The expectation is that people would generally use Factory and Bean instead of implementing the Provider interface.

@Singleton
public class FooProvider implements Provider<Foo> {

  private final Bazz bazz;

  FooProvider(Bazz bazz) {
    this.bazz = bazz;
  }

  @Override
  public Foo get() {
    // maybe do interesting logic, read environment variables ...
    return new BasicFoo(bazz);
  }
}