The same example from above can also be done using what is known as field injection. Instead of annotating the constructor with @Inject
, we annotate the fields we wish to have injected
public class Spaceship {
@Inject
private PropulsionSystem propulsionSystem;
@Inject
private NavigationSystem navigationSystem;
public void launch() throws FlightUnavailableException {
if (propulsionSystem.hasFuel()) {
propulsionSystem.engageThrust();
} else {
throw new FlightUnavailableException("Launch requirements not met. Ship needs fuel.");
}
}
}
Note that getter/setter methods are not required for field injection to work. Also note that the field does not need to be public and can in fact be private, though it cannot be final. Making the field private will, however, make writing tests for the code more difficult, as the tests will have to use reflection to modify the field if it does not have a setter.
Also note that constructor injection and field injection can be used in tandem if desired, though it should be very carefully evaluated whether or not it makes sense to do so on a case by case basis. Perhaps it is necessary when working with legacy code to add a dependency to the class without modifying the constructor signature for some peculiar reason.
public class Spaceship {
private PropulsionSystem propulsionSystem;
@Inject
private NavigationSystem navigationSystem;
@Inject
public Spaceship(PropulsionSystem propulsionSystem) {
this.propulsionSystem = propulsionSystem;
}
public void launch() throws FlightUnavailableException {
if (propulsionSystem.hasFuel()) {
propulsionSystem.engageThrust();
} else {
throw new FlightUnavailableException("Launch requirements not met. Ship needs fuel.");
}
}
}