javadependency-injectiondagger

How do I supply an object to a parent constructor when that object is normally is dependency injected?


Suppose I have these made-up classes (I know nothing about cars btw)

@Singleton
class ElectricEngine implements Engine {
}

class Vehicle {
  private final Engine engine;
  Vehicle(Engine engine, SteeringSystem ss, ...) {
    this.engine = engine;
  }
}

Normally, child classes would be built in this way

class Tesla extends Vehicle {
  @Inject
  Tesla(ElectricEngine engine, SteeringSystem ss) {
    super(engine, ss);
  }
}

What I'd like to do not have the child specify the Engine and have a class such as

class ElectricVehicle extends Vehicle {
  ElectricVehicle(SteeringSystem ss) {
   super(electricEngine???, ss);
  }
}

class Tesla extends ElectricVehicle {
  @Injected
  Tesla(SteerByWireSystem ss) {
    super(ss);
  }
}

The question is, how can ElectricVehicle get the ElectricEngine object to pass to its parent?

I considered doing field injection but not sure if that would solve it and also not a fan of it based on this.

Any ideas?


Solution

  • If you want to use the Injection to handle your bean, you'll need to inject something.

    An alternative, pure Java, solution to a singleton is to have the class hold it's own singleton instance:

    class ElectricEngine implements Engine {
        private static ElectricEngine instance;
    
        public static ElectricEngine getElectricEngine() {
            if(instance == null) {
                instance = new ElectricEngine();
            }
            return instance;
        }
    }
    
    class Tesla extends ElectricVehicle {
      @Injected
      Tesla(SteerByWireSystem ss) {
        super(ElectricEngine.getElectricEngine(), ss);
      }
    }
    

    Additional ideas based on authors comment. Reverting to Spring because it's what I know best.

    I would probably go for something like this:

    class Tesla extends ElectricVehicle {
        @Autowired
        Tesla(ElectricEngine electricEngine, SteerByWireSystem ss) {
            super(electricEngine, ss);
        }
    }
    
    @Component
    class TeslaFactory {
        private final ElectricEngine electricEngine;
        
        @Auwotired
        public TeslaFactory(ElectricEngine electricEngine) {
            this.electricEngine = electricEngine;
        }
        
        @Bean
        public Tesla newTesla(SteerByWireSystem ss) {
            return new Tesla(electricEngine, ss);
        }
    }
    

    In general, I prefer the more controlled way of creating beans via methods rather than deferring it to the injection framework.