3 Replies Latest reply on May 11, 2009 10:54 AM by Brian Cowdery

    @PersistenceContext injection into superclass defined in a s

    Brian Cowdery Newbie

      This is a weird one - so let me give a little bit of background information first. We're using Seam for some new development, and we have a large shared objectmodel jar that contains EJB3 entities and stateless session bean DAO's (following the caveat emptor GenericDAO pattern from the hibernate examples).

      Since we started using Seam, we noticed that the only way to get the Seam Managed Persistence Context was to use the Seam @In annotation... which works - but if we update all our DAO's to use @In we'll break our non-seam applications that use the objectmodel as a plain JPA implementation.

      We externalized the DAO superclass (which contains our injectable EntityManager) into 2 separate "client" jar's. One client jar using the Seam @In annotation, and one using the @PersistenceContext annotation for compatability. This way we can grab our core objectmodel jar, and an appropriate client jar to provide the correct EntityManager depending on the vendor/framework we're using.

      so now we have
      - objectmodel-core.jar (contains persistence.xml, Entity beans and DAO's)
      - objectmodel-seam-client.jar (DAO super class, with appropriate EM injection)
      - objectmodel-jpa-client.jar ""


      The problem is that the injected EntityManager is ALWAYS null! For some reason the container will not inject the EntityManager into the DAO superclass if its located in a different jar. It worked fine when it was all self contained in a single jar file.

      The EAR layout looks like this:

      application.ear
       |- objectmodel.jar (ejb module)
       |-- persistence.xml
       |- application-web.war (web module)
       |- /lib
       |-- objectmodel-client.jar
      



      A DAO from objectmodel.jar uses the GenericDAOImpl which is satisfied at runtime by the appropriate "client" jar.
      @Stateless
      @Clustered
      @Local(UserDAO.class)
      @Remote(UserDAO.class)
      public class UserDAOImpl extends GenericDAOImpl<User, Long> implements UserDAO {
      
       public User findUserByUsername(String username) {
       Map<String, Object> params = new HashMap<String, Object>();
       params.put("username", username);
       return executeSingleResultNamedQuery("User.findByUsername", params);
       }
      }
      



      JPA GeneridDAOImpl - contained in the client jar
      public class GenericDAOImpl<T, ID extends Serializable> extends BaseGenericDAO<T, ID> {
      
       protected EntityManager em;
      
       @PersistenceContext(unitName = "objectmodelOLTP")
       public void setEntityManager(EntityManager em) {
       this.em = em;
       }
      
       protected EntityManager getEntityManager() {
       if (em == null)
       throw new IllegalStateException("EntityManager has not been set on DAO prior to usage");
       return em;
       }
      }
      



      Shouldn't the injection/annotations be handled regardless of where the superclass is?

      From a class-loading point of view this does work. I can call implementation methods from GenericDAOImpl from my objectmodel-core DAO's without issue. I'm not getting any ClassNotFoundExceptions or linkage errors - the only problem is that I cannot get the EntityManager to be injected.


      This may be a roundabout solution as well... if anyone has any better ideas on how to dynamically inject an appropriate EntityManager in a Seam app vs a non-Seam app i'd love to hear it.

      My last ditch effort will be hacking up some build files to grab the appropriate class at compile time and create multiple versions of the objectmodel-core. I really want to avoid this :\




      Oh yeah... We're using JBoss 4.2.2GA