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

    @PersistenceContext injection into superclass defined in a s

    bcowdery

      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

        • 1. Re: @PersistenceContext injection into superclass defined in
          jaikiran

           

          |- /lib
          |-- objectmodel-client.jar


          jar(s) within the lib folder of the EAR are considered plain libraries and not as deployments. So no injection happens in them. You might want to move that objectmodel-client.jar outside the lib folder to the root of the EAR (and i guess additionally mark it as a module in the application.xml - i don't have access to my work system so can't confirm whether application.xml change is required).


          • 2. Re: @PersistenceContext injection into superclass defined in
            bcowdery

            I tried that as well, although i had the objectmodel-client.jar marked as an EJB module in the application.xml (maybe a java module would be more appropriate?).

            I'll give it another try and let you know how it goes.

            • 3. Re: @PersistenceContext injection into superclass defined in
              bcowdery

              I move the client jar into the root of the .ear file, and marked it as an EJB module in the application.xml - Everything's working as expected now. I can't get the Seam interceptor working on my objectmodel-seam-client.jar but that's a post for a different forum.

              I have no idea why this didn't work the first time I tried it, maybe JBoss got "stuck" on the deployment and wasn't the exploded deploymen (i dunno, i've seen that happen before so its just a guess).

              Thanks for your help.