Hi, all,
I'm looking for suggestions on how to inject runtime dependencies into JPA entities retrieved from Hibernate. My problem is essentially this:
I have a number of different subclasses of a Transaction object. Each Transaction subclass has different behavior when it is executed, and requires a different set of dependencies from the environment. These Transaction objects are managed as JPA entities by Hibernate, so I can't effectively use Guice for dependency injection to populate the instances with their environmental dependencies as I do in the rest of my application.
To get around this problem, I've taken an approach that's somewhat akin to the Visitor pattern, as follows:
public abstract class Transaction {
// ...snip...
public abstract void apply(Transactor transactor);
}
public class TransactionA extends Transaction {
public void apply(Transactor transactor) {
transactor.execute(this);
}
}
public class TransactionB extends Transaction {
public void apply(Transactor transactor) {
transactor.execute(this);
}
}
// other Transaction subclasses with the same boilerplate
public interface Transactor {
public void execute(TransactionA trans);
public void execute(TransactionB trans);
// corresponding methods for other transaction types.
}
public class BeginTransactor {
@Inject
private Foo execAdep;
public void execute(TransactionA trans) {
execAdep.doSomething(...)
}
@Inject
private Bar execBdep;
public void execute(TransactionB trans) {
execBdep.doOther(...)
}
}
I have various implementations of Transactor for different parts of the transaction lifecycle. These can be dependency-injected using Guice into the context in which I want to process the transactions, where I simply call:
Transactor transactor = injector.getInstance(BeginTransactor.class); //Guice injection
Transaction t = ... //get a transaction instance
t.apply(transactor);
What I don't like about this approach is (1) Not every type of transaction should be executable in each lifecycle phase, but every Transactor must implement an execute() method for every transaction subclass and (2) Essentially none of the injected dependencies are used for processing more than one transaction type.
Essentially, my Transactor interface & implementations have a lot of unrelated crud glopped together. Ideally I'd just have the execute() method on the transaction object itself, but I don't want the calling code to have to know about the type of the Transaction or the dependencies that it requires. Also, this could make testing harder because I couldn't easily mock out the execute() method if it were a concrete method on the Transaction object. Using the Transactor interface means that I can easily mock it out as needed.
Can anyone suggest how to address this problem in a typesafe manner that doesn't result in a bunch of mostly-unrelated behavior being glommed together in the Transactor, but keeps the testability and allows for dependency injection?