9 Replies Latest reply on Jun 7, 2011 3:13 AM by Leo van den berg

    How to deploy JPA entities in an extra jar file?

    Daniel Behrwind Newbie

      Hi,


      I'm developing an application with several modules (different ear files) that have several JPA entities in common. Thus, I'd like to provide the modules with one jar file containing the annotated JPA entities. I've put this jar into the ear's lib directory but when I try to persist an entity I always get an IllegalArgumentException, telling me that the eneity is unknown:


      java.lang.IllegalArgumentException: Unknown entity: com.symtavision.symtaweb.lib.AnalysisJob
      at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:215)
      at org.jboss.ejb3.entity.TransactionScopedEntityManager.persist(TransactionScopedEntityManager.java:182)
      at org.jboss.seam.persistence.EntityManagerProxy.persist(EntityManagerProxy.java:135)
      at com.symtavision.symtaweb.clientinterface.handler.AnalysisRequestHandler.createAnalysisJob(AnalysisRequestHandler.java:54)
      at com.symtavision.symtaweb.clientinterface.handler.AnalysisRequestHandler.commissionAnalysisJob(AnalysisRequestHandler.java:38)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
      at java.lang.reflect.Method.invoke(Method.java:597)
      at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:112)
      at org.jboss.ejb3.interceptor.InvocationContextImpl.proceed(InvocationContextImpl.java:166)
      at org.jboss.seam.intercept.EJBInvocationContext.proceed(EJBInvocationContext.java:44)
      at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:56)
      at org.jboss.seam.transaction.RollbackInterceptor.aroundInvoke(RollbackInterceptor.java:31)
      at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
      at org.jboss.seam.core.MethodContextInterceptor.aroundInvoke(MethodContextInterceptor.java:42)
      at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
      at org.jboss.seam.persistence.EntityManagerProxyInterceptor.aroundInvoke(EntityManagerProxyInterceptor.java:26)
      at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
      at org.jboss.seam.persistence.HibernateSessionProxyInterceptor.aroundInvoke(HibernateSessionProxyInterceptor.java:27)
      at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
      at org.jboss.seam.intercept.RootInterceptor.invoke(RootInterceptor.java:107)
      at org.jboss.seam.intercept.SessionBeanInterceptor.aroundInvoke(SessionBeanInterceptor.java:50)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
      at java.lang.reflect.Method.invoke(Method.java:597)
      at org.jboss.ejb3.interceptor.InvocationContextImpl.proceed(InvocationContextImpl.java:118)
      at org.jboss.ejb3.interceptor.EJB3InterceptorsInterceptor.invoke(EJB3InterceptorsInterceptor.java:63)
      at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
      at org.jboss.ejb3.entity.ExtendedPersistenceContextPropagationInterceptor.invoke(ExtendedPersistenceContextPropagationInterceptor.java:57)
      at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
      at org.jboss.ejb3.entity.TransactionScopedEntityManagerInterceptor.invoke(TransactionScopedEntityManagerInterceptor.java:54)
      at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
      at org.jboss.ejb3.AllowedOperationsInterceptor.invoke(AllowedOperationsInterceptor.java:47)
      at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
      at org.jboss.aspects.tx.TxPolicy.invokeInCallerTx(TxPolicy.java:126)
      ... 103 more



      So, what steps are necessary to make Hibernate know the entities in the jar?


      Thanks for any help!


        • 1. Re: How to deploy JPA entities in an extra jar file?
          thierry accart Newbie

          In your persistence.xml file you'd have in persistence-unit a jar-file
          item contains name of ejb's jar file.


          See example in this page on jboss ejb3



          Rgds
                    


          • 2. Re: How to deploy JPA entities in an extra jar file?
            Monkey Den Master
            I'm trying a similar configuration.  In an attempt to modularize my entity model, I have my it as a separate artifact, deployed to the root of the ear.  Mine is a little different in that I have entities from 3 different schemas in the same jar file (or course let me know if this is even possible).

            In any case, I'm a little confused by the documentation found at this link.  The docs seem to indicate that the persistence.xml with the <jar-file> element is also the archive containing the entity beans:

            You must also define a persistence.xml file that resides in the META-INF folder of the .jar file.
            <persistence>
               <persistence-unit name="manager1">
                   <jta-data-source>java:/DefaultDS</jta-data-source>
                   <jar-file>../MyApp.jar</jar-file>
                   <class>org.acme.Employee</class>
                   <class>org.acme.Person</class>
                   <class>org.acme.Address</class>
                   <properties>
                        <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
                        <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
                   </properties>
               </persistence-unit>
            </persistence>

            I have a few questions with this:
            1.  First, is my interpretation correct?  If yes, why would you need <jar-file> since, given the documentation, it is assumed that the "current" jar file is the archive containing the entities?

            2.  Given the reference "../MyApp.jar", what is the current directory assumed to be?  The "MyApp.jar/META-INF" directory, where the persistence.xml lives?  I can't seem to move up 2 directories (outside of the containing jar) using "../../MyApp.jar".

            3.  Would I also need to include a ejb-jar.xml file (including the seam interceptor configuration) in the same entity archive?

            What I would expect is:
            1.  my-app-bizlogic.jar contains a persistence.xml which references a jar file (common-data-model.jar).  The persistence.xml file references the class mappings for each of the 3 persistence units.  The problem with this is, it can't be in a jar file, because I can't cd out of the jar using "../../MyApp.jar".  Looks like it needs to be in the ear/META-INF, so I can get to the common-data-model.jar in the root using "../../common-data-model.jar".

            Here is a semi-graphical representation of how I would expect it to work
            my-app.ear
              \-lib [dir]
              \-my-app.war [dir]
              \-my-bizlogic.jar (seam backing beans)
                \-[backing meanbeans]
                \-META-INF/persistence.xml (containing <jar-file> reference and class list, grouped by persistence unit)
              \-common-data-model.jar
                \-[entities]

            As I said, I can't change directory outside of the jar containing my business logic, so maybe persistence.xml should go in my-app.ear/META-INF?

            Let me know if that makes any sense at all, and whether I can clarify anything.  Thanks for any guidance!
            • 3. Re: How to deploy JPA entities in an extra jar file?
              Stuart Douglas Master

              I have an ear with several jar files with a persistence unit shared between them.
              To do this you need to split all your entities into a separate jar file, and put the persistence.xml in the META-INF of this jar. This file cannot have any EJB's in it, as this file must be delared as

              <java>

              rather than
              <ejb>

              in application.xml. There is no need for a
              <jar-file>

              entry in persistence.xml, this is used for something else (see bottom of post).


              If you then want to access this persistence unit in an EJB using @PersistenceUnit then you need to do the following in Jboss 4.2:


              @PersistenceContext(unitName = "../myEntityFile.jar#main")



              (assuming that the persistence unit name is main). In Jboss 5 (and I assume any other spec compliant AS) the unit name is simply main. The persistence unit can be bound to JNDI as per normal.



              If you want to share the persistence unit between multiple ears then this will not help you, but I belive there have been some threads about this on the forum recently.


              The jar-file entry does not let you share persistence units between multiple EJB jars, it lets you reference entities stored in a different jar to the jar that contains the persistence unit. So if you have two separate EJB jars that reference a different jar with entities in it you will end up with two separate persistence units with the same entities rather than a shared persistence unit.

              • 4. Re: How to deploy JPA entities in an extra jar file?
                Jason Long Novice

                Will this work with entities, SLSB, and SFSB in different jars, but sharing the same persistence unit?


                I am trying to modularize a large application that I built.  I need to reuse parts in other applications.


                For example the application contains contact manager functionality.  I would like to have a contacts.jar and be able to use this in other applications.


                The contacts need to share the same persistence unit as other entities in the application.


                I would rather not list all of the entities, but I am willing to do so if it will work.


                Does anyone here have this working with Seam and JBAS?


                If so can you please post the details including where and how to package the persistence.xml, what is needed in the individual jars to make it work, and an example of a persistence.xml?

                • 5. Re: How to deploy JPA entities in an extra jar file?
                  Leo van den berg Master

                  Yes, I have this working (finally). I have two jars containing the generic part and a second jar with a specific part of my domain model. These fikles are in the LIB-directory of my default server OUTSIDE my application. I place the persistency.xml plus all SB's in a third jar which I deploy normally in the deploy directory.


                  I found a huge difference between JBoss 5.0 an 5.1 In the first I could deploy everything defining the jar-file in the persistency.xml, BUT since 5.1 this doesn't work anymore and I need to name each entity separatly. My Seam-project uses a normal WAR and it uses all parts.


                  You could think that I would stick to JBoss 5.0, but that produces another problem that first the Application war is loaded an then the Entity-jars. In JBoss 5.1 this works as needed , so first the persistency and then the WAR.


                  For a full build I create an EAR which inclues the persistency jar and the WAR and this is my preferred solution, because I want to re-use my domain model independently from the rest of  my application in client code. Maybe of interest to you I annotated all claaaes with XML annotations for use in RestEasy which is now a piece of cake. I also added all common SB-interfaces to the common model.


                  It looks complex but with the help of MAven the builds are really easy , fully documented,  maintanable and more important portable to other developers.


                  Hopefully this helps,


                  Leo


                  • 6. Re: How to deploy JPA entities in an extra jar file?
                    Jason Long Novice

                    1.  So do you put pesistency.jar in the lib or the root of the ear?
                    2.  Would you post a generic example of your persistence.xml?
                    3.  Have you tired this on JBAS 4.2.x?

                    • 7. Re: How to deploy JPA entities in an extra jar file?
                      Leo van den berg Master

                      Hi Jason,


                      The jar is placed in the Root of the EAR. For testing it's deployed directly in the deploy directory (because it also contains SB's).


                      An example of my persistence.xml




                      <?xml version="1.0" encoding="UTF-8"?>
                      <!-- Persistence deployment descriptor for dev profile -->
                      <persistence xmlns="http://java.sun.com/xml/ns/persistence"
                           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                           xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
                           version="1.0">
                      
                           <persistence-unit name="DomainModel">
                                <provider>org.hibernate.ejb.HibernatePersistence</provider>
                                <jta-data-source>java:DomainModel</jta-data-source>
                                
                                <class>es.esam.itsdomain.common.ValueObject</class>
                                      <!-- AND ALL THE OTHER CLASSES -->
                      
                                <properties>
                                     <property name="hibernate.dialect"
                                          value="org.hibernate.dialect.MySQLDialect" />
                                     <property name="hibernate.cache.use_query_cache"
                                          value="true" />
                                          
                                     <property name="hibernate.show_sql" value="true" />               
                                     <property name="hibernate.format_sql" value="true" />
                                     <property name="jboss.entity.manager.jndi.name"
                                          value="java:/DomainModelEntityManager" />
                                     <property name="jboss.entity.manager.factory.jndi.name"
                                          value="java:/DomainModelEntityManagerFactory" />
                                     <property name="hibernate.search.default.directory.provider"
                                          value="org.hibernate.search.store.FSDirectoryProvider" />
                                     <property name="hibernate.search.default.indexBase"
                                          value="../server/default/lucene/indexes" />
                       
                                     <property name="hibernate.ejb.event.post-insert"
                                          value="org.hibernate.ejb.event.EJB3PostInsertEventListener,org.hibernate.envers.event.AuditEventListener" />
                                     <property name="hibernate.ejb.event.post-update"
                                          value="org.hibernate.ejb.event.EJB3PostUpdateEventListener,org.hibernate.envers.event.AuditEventListener" />
                                     <property name="hibernate.ejb.event.post-delete"
                                          value="org.hibernate.ejb.event.EJB3PostDeleteEventListener,org.hibernate.envers.event.AuditEventListener" />
                                     
                                     
                                     <property name="hibernate.ejb.event.pre-collection-update"
                                          value="org.hibernate.envers.event.AuditEventListener" />
                                     <property name="hibernate.ejb.event.pre-collection-remove"
                                          value="org.hibernate.envers.event.AuditEventListener" />
                                     <property name="hibernate.ejb.event.post-collection-recreate"
                                          value="org.hibernate.envers.event.AuditEventListener" />
                      
                                     <property name="org.hibernate.envers.auditTablePrefix"
                                          value="AUD_" />
                                     <property name="org.hibernate.envers.auditTableSuffix"
                                          value="" />
                                     <property name="org.hibernate.envers.revisionFieldName"
                                          value="ver_rev" />
                                </properties>
                           </persistence-unit>
                      </persistence>
                      



                      As you can see it also contains the settings for Lucene (for Text search) and Envers auditing. I've tried it with several servers (including JBOSS 4.2) but it needs additional tuning per version. This version works like this under 5.1. The main problem was that Hibernate is (I'm assuming this) is not able to find annotated classes under the lib directory. However under JBoss 5.0 it worked when I use the reference to the jar file (?). I really want to separate the domainmodel from the rest of the application because I want it used in client code and I don't want to load a lot of dependencies if there isn't a real need to do that. As mentioned I use Maven for development which helps a lot (especially the dependency -stuff) especially if you're thinking of using search and envers you need to reference the right jars in your development AND deploy environment.


                      The thing I did was testing the different configurations with a simple set of entities (with some complex associations to be sure it REALLY works) and an empty database. Setting the create-drop property to true will get you the fresh database every time you start the server. I know it can take some (boring) days, but it helps getting you on the road without any further problems.


                      When you have the persistency working correctly, adding Seam will be a piece-of-cake. make sure you have the persistency manager configured correctly in components.xml and add additional setting if you intend to use ejb3's persistsncy context.


                      If you need some furher help don't hesitate to ask this or Hibernate's forum.


                      Good Luck,


                      Leo

                      • 8. Re: How to deploy JPA entities in an extra jar file?
                        H G Newbie

                        Hi Leo,


                        I'm trying tho share entity packaged in separate JAR between two WARs without success. I'm using Seam 2.1.2 on JBoss 5.1.


                        As I can see you have two solutions for that. I'm trying to accomplish the first. Can you plese share more details about the first solution without using EAR.





                        1. The persitence.xml that you publicated is the same for the both solutions?

                        2. How are you packaging the entity to JAR (how resolve dependency on compile)?

                        3. If you drop the entity JAR to LIB-directory of my default server how are you building the WAR project without resolving the reference to the entity?



                        Anybody know if in JBoss 6.0 can be used persistence.xml (with jar-file) and entity both packaged to JAR as is mentioned in the specification?

                        • 9. Re: How to deploy JPA entities in an extra jar file?
                          Leo van den berg Master

                          Hi,


                          If you don't want to create an EAR (which is a far better solution for this) you can put the jar with the entity beans in you {server}/lib directory AND you must add every class in the persistence.xml (just like the example). The other trick is to create a single jar with all the entities and the persistence.xml. In this case Hibernate will find the entities in the jar and will do the same.


                          The following works with JBOSS As 5.1: just build the WAR projects and drop them in the deploy directory. They can reference the PersistenceContext without a problem. Be awar that EJB's (which you can include in the jar) are referenced as local beans (without the EAR-prefix).


                          I do this for testing only. Everything goes into an EAR at the end !!!


                          Leo