0

I was wondering how to solve the following problem using Spring dependency injection:

Given that I have a list of Transactions of different types, I'd need to process them based on their TransactionType. So I’d have a TransactionController with a TransactionService as such:

public class TransactionController {
    private TransactionService transactionService;
    public void doStuff(List<Transaction> transactions) {
        for (Transaction transaction : transactions) {
            // use the correct implementation of transactionService based on the type
            transactionService.process(transaction);
        }
    }
}

public interface TransactionService {
    void process(transaction);
}

Without using Spring IoC, I would use a Simple Factory pattern to return the implementation based on the Type enum:

public class TransactionServiceFactory {
    public TransactionService(TransactionType transactionType) {
        // switch case to return correct implementation.
    }
}

How can I achieve the same injecting the TransactionService? I can't use the @Qualifier annotation, as implementation depends on the TransactionType. I've stumbled upon an article in the spring docs showing Instantiation using a factory method, but I cannot figure how to pass arguments to it.

I believe I probably have to use a different design with Spring IoC. I guess since I've always used the Simple Factory, Factory and Abstract Factory patterns, I can’t see a different way of solving this…

Can someone also please format this for me? The android app doesn't seem to do this, sorry!

Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
Tarek
  • 3,080
  • 5
  • 38
  • 54

2 Answers2

2

In this case, factory pattern or similar is the correct solution, IMHO. Just implement a factory/registry/locator object and inject that using Spring. The rest is as usual. Injection happens when your object is created, but you need different implementations of the service during runtime. In this case, only service locator, factory or similar patterns make sense.

kaqqao
  • 12,984
  • 10
  • 64
  • 118
  • But how would the injection framework switch the implementation in the middle of doStuff method? Even with the darkest of AoP magic, you wouldn't be able to swap objects in the middle of the loop. And even if you could, it would be a solution to stay away from. – kaqqao Sep 11 '14 at 19:11
  • Right... What if Spring had some sort of AbstractFactory that'd be called when using the uninstanciated service, then it'd check for a parameter meta-attribute and use it in the application configuration? Or have I gone completely insane? I think I need a break... – Tarek Sep 11 '14 at 19:18
  • Well... as far as I know, there is no such thing OOB and it sounds too situational for a generic solution. You can, of course, make your own wrapper around the TransactionService that does whatever, but then you'd effectively be implementing one of the patterns from my original response. Heck, you could even make it somewhat generic, to e.g. find beans with Qualifiers with type names. – kaqqao Sep 11 '14 at 19:27
  • yep, I'll make a PoC injecting the factory and in the factory class injecting each service to be returned... – Tarek Sep 15 '14 at 11:44
1

You can use Map property injection in this case:

**private Map<TransactionServiceMap>  transactionServiceMap;**


<!-- results in a transactionServiceMap(java.util.Map) call -->
**<property name="transactionServiceMap">
    <map>
        <entry key="TRANSACTION_TYPE_1" value-ref="transactionService1"/>
        <entry key ="TRANSACTION_TYPE_2" value-ref="transactionService2"/>
    </map>
</property>**

and in modify the for loop as stated below:

public void doStuff(List transactions) {

        for (Transaction transaction : transactions) {

            // use the correct implementation of transactionService based on the type

            TransactionService transactionService = transactionServiceMap
                                          .get(transaction.getType());

            transactionService.process(transaction);



        }

    }
Hansraj
  • 174
  • 5
  • That's interesting too... Well it seems there's no way to directly get the implementation... – Tarek Sep 11 '14 at 19:26
  • You will always have different service instance for specific transaction type. So you can provide those instances through injection directly. Even if mutiple transaction type belongs to same service instance you can provide the same reference for both trasaction type. – Hansraj Sep 11 '14 at 19:31