Adam Bien's Weblog
JPA Injection Shortcomings and Possible Workaround
I got a really interesting question/suggestion as a feedback for p4j5 and the PDO pattern. If you are going to realize rich domain objects, sometimes it's necessary to access the resources like EntityManager from inside a JPA-Entity. Eg. sometimes it is useful to search for entites, access other Session Beans/Services etc. The problem here - dependency injection in JPA is not supported by the EJB-Container (now).
However simple Strategy algorithms, can be injected in e.g. the Service Facade, or Persitent Domain Object Facade (checkout p4j5)
Sample:
/** SessionBean Discount Strategy */
@Stateless
public class DiscountStrategyImpl implements DiscountStrategy { ... }
/** ShoppingCart uses a DiscountStrategy to calculate discount */
@Entity
public class ShoppingCart
{
@Transient
private DiscountStrategy strategy;
..
void setDiscountStrategy(DiscountStrategy discountStrategy) { this.strategy = discountStrategy; }
}
/** Facade for ShoopingCart */
@Stateless
public class ShoppingCartService
{
@EJB
private DiscountStrategy strategy;
public ShoppingCart findById(Object id)
{
final ShoppingCart cart = em.find(ShoppingCart.class, id);
cart.setDiscountStrategy(strategy);
return cart;
}
}
The solution only works for the "master", and not dependent entities, however the master-entity could propagate the strategy to the children as well. This could change in Java EE 6 with the "Singleton Beans".
Thanks to Thomas Bauer for the suggestion of this pattern. He suggested the name "Service Injection". However "Strategy Injection" could be a better name for this specific case above.
Btw. there are now 24 approved observers in p4j5.
Posted at 09:28AM Sep 11, 2007 by Adam Bien in Java EE 5 Architectures | Kommentare[5]
[This entry is based on / extends my books: Enterprise Architekturen, Leitfaden fuer effiziente Software-Entwicklung and: Java EE 5 Architekturen, Patterns und Idiome]



Interesting, if a bit verbose as a pattern. I've been looking for a good answer to this problem. I certainly like your idea of rich domain objects, I think if java had mixins this would become effortlessly simple:
@Entity public class ShoppingCart { .. }
//maybe?
mixin cart := (new ShoppingCart(), new DiscountService(), new ShoppingService() ...);
//then invoke any mixed service on the cart
cart.applyDiscount();
cart.findById(cart.getRelatedCart().getId());
//etc.
Dhanji.
Gesendet von Dhanji am September 11, 2007 at 09:42 AM CEST #
If you don't have problems with using vendor specific extensions, than often there are simpler ways:
For instance in OpenJPA (interface OpenJPAEntitiManager(SPI) ) you have a "addLiveCycleListener" method where you have the possibility to instanciate your listener yourself, thus having all the power of real dependency injection (on all objects managed by JPA).
This method is standardized in JDO2.0 PersistenceManager, so its a shame that such a usefull thing didn't get into JPA.
Since we still use JDO instead of JPA we are proud to have a rich persistent domain model, where each object knows the central EventDispatcher for synchronizing various views.
Gesendet von Stefan Hansel am September 11, 2007 at 11:11 AM CEST #
Actually I have made very good experiences with Hibernate's UserType mechanism. In one project we even used User Types to lazily retrieve Data from a legacy banking backend.
IMHO something like UserTypes or JDO's CustomMappers should be specified in JPA (although I am aware that this is one thing that will be tough one to negotiate between the vendors in the JPA EG)
Gesendet von Michael Plöd am September 11, 2007 at 07:09 PM CEST #
Michael,
thank your for the comment. Regardless how hard it is to convince the EGs, I will try it :-),
thanks!
Gesendet von Adam Bien am September 11, 2007 at 10:10 PM CEST #
Spring does something similar (though much cleaner) with @Configurable. I don't really get the point of rich domain objects that need a service facade though.
Gesendet von Jose Noheda am September 16, 2007 at 02:00 PM CEST #