Search code examples
javaspringdependency-injectioncommand-pattern

How to inject a repository in command design pattern?


In few classes I have similar else if statements that I wanted to replace using the command pattern. The idea was to externalize the else if bodies and depending on what service calls it use its repositories. Problem is that I can't seem to find a way to get the repositories injected into my class. Ill explain better in the example:

part of code that should use command pattern:

private HashMap<String, BnResponseHandler> commandMap = new HashMap<>();

for (CustomerDelivery customerDelivery : list) {
    commandMap.put("true", new SuccessfulResponse(customerDelivery));
    commandMap.put("1", new ResponseCodeOne(customerDelivery));
    commandMap.put("2", new ResponseCodeTwo(customerDelivery));
    commandMap.put("3", new ResponseCodeThree(customerDelivery));
    BnResponseHandler bnResponseHandler = new DefaultHandler(customerDelivery);

    if(response.isSuccessful()){
        commandMap.get(String.valueOf(response.isSuccessful())).handle();
    } else if (response.getResponseCode() != null
        && !response.getResponseCode().equals("")){
        commandMap.get(response.getResponseCode()).handle();
    } else {
        bnResponseHandler.handle();
    }
} 

the interface:

public interface BnResponseHandler {

    void handle();
}

and the interface implementation:

@Component
public class ResponseCodeOne implements BnResponseHandler {

    @Autowired
    private FabricationRepository fabricationRepo;
    private Fabrication fabrication;

    @Autowired
    private MovementsRepository movementsRepository;
    private StockMovements stockMovements;

    @Autowired
    private CustomerDeliveryRepository customerDeliveryRepo;
    private CustomerDelivery customerDelivery;

    public ResponseCodeOne() {
    }

    public ResponseCodeOne(Fabrication fabrication) {
        this.fabrication = fabrication;
    }

    public ResponseCodeOne(StockMovements stockMovements) {
        this.stockMovements = stockMovements;
    }

    public ResponseCodeOne(CustomerDelivery customerDelivery) {
        this.customerDelivery = customerDelivery;
    }

    @Override
    public void handle() {
        if (fabrication != null) {
            fabrication.setFG_ETAT("D");
            fabrication.setLB_ETAT("");
            fabricationRepo.save(fabrication);
        } else if (stockMovements != null) {
            stockMovements.setFG_ETAT("D");
            stockMovements.setLB_ETAT("");
            movementsRepository.save(stockMovements);
        } else if (customerDelivery != null) {
            customerDelivery.setFG_ETAT("D");
            customerDelivery.setLB_ETAT("");
            customerDeliveryRepo.save(customerDelivery);
        }
    }
}

So the big picture was to set ResponseCode classes for every possible response code I could get (in this case 1) and inside of those classes do some business logic that depends on the repository beans. It should also be flexible so that I can use the ResponseCodeOne class for multiple different cases(meaning fabrication, stockMovements and customerDelivery). The problem I am having is that my repositories don't get injected this way and I keep on getting an null pointer exception. Is there a way to cleanly inject my repository beans?


Solution

  • The main issue I see is that you are creating your own instances of your response code classes using the new keyword, which means that Spring will not autowire them. To get them successfully autowired you will need to inject instances of them into the class where your for loop is located. However, this introduces a secondary issue where you can no longer provide an object from your for loop to the constructor of your response code instances. To solve this problem you can pass the Fabrication/StockMovements/CustomerDelivery instance as an argument to handle().