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.

Comments:

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.

Posted by Dhanji on September 11, 2007 at 11: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.

Posted by Stefan Hansel on September 11, 2007 at 01:11 PM 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)

Posted by Michael Plöd on September 11, 2007 at 09:09 PM CEST #

Michael,

thank your for the comment. Regardless how hard it is to convince the EGs, I will try it :-),

thanks!

Posted by Adam Bien on September 12, 2007 at 12:10 AM 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.

Posted by Jose Noheda on September 16, 2007 at 04:00 PM CEST #

Has there been any progress on this front in the past 3 years? Anything new in Java EE 6 or CDI that allows injection of managed beans to create richer domain objects?

Thanks.

Posted by Naresh Bhatia on January 21, 2011 at 09:11 PM CET #

Post a Comment:
  • HTML Syntax: NOT allowed
...the last 150 posts
...the last 10 comments
License