Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does OpenJPA work well with Glassfish?

Is anyone successfully using OpenJPA with Glassfish?

I'm trying to use OpenJPA 2.1 with Glassfish 3.1 Open Source. I've followed the instructions to integrate the two here -> http://weblogs.java.net/blog/ss141213/archive/2006/07/using_openjpa_a.html

I have a very simple EJB project in Eclipse Indigo with the following:

  • com.rares.test.Person - @Entity
  • com.rares.test.PersonManager - interface
  • com.rares.test.PersonDao - @Stateless

However, when I try to deploy I get a ClassNotFoundException on my Person @Entity. The complaint seems to be the Person parm on a create method that's being implemented in my PersonDao (see all code below).

I've tried the same project without specifying a provider in my persistence.xml and the project works fine (able to persist a Person @Entity to a PERSON table in MySql). I think I'm using EclipseLink if I don't specify a provider (please correct me if I'm wrong). This leads me to believe that I haven't configured OpenJPA with Glassfish correctly.

Stack Trace

Caused by: java.lang.IllegalArgumentException: java.lang.ClassNotFoundException: com.rares.test.Person
    at serp.util.Strings.toClass(Strings.java:164)
    at serp.util.Strings.toClass(Strings.java:108)
    at serp.bytecode.BCClass.getType(BCClass.java:566)
    at org.apache.openjpa.enhance.PCEnhancer.<init>(PCEnhancer.java:283)
    at org.apache.openjpa.enhance.PCEnhancer.<init>(PCEnhancer.java:254)
    at org.apache.openjpa.enhance.PCClassFileTransformer.transform0(PCClassFileTransformer.java:144)
    at org.apache.openjpa.enhance.PCClassFileTransformer.transform(PCClassFileTransformer.java:124)
    at org.apache.openjpa.persistence.PersistenceProviderImpl$ClassTransformerImpl.transform(PersistenceProviderImpl.java:294)
    at org.glassfish.persistence.jpa.ServerProviderContainerContractInfo$1.transform(ServerProviderContainerContractInfo.java:98)
    at com.sun.enterprise.loader.ASURLClassLoader.findClass(ASURLClassLoader.java:742)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2427)
    at java.lang.Class.privateGetPublicMethods(Class.java:2547)
    at java.lang.Class.getMethods(Class.java:1410)
    at com.sun.enterprise.deployment.EjbDescriptor.addAllInterfaceMethodsIn(EjbDescriptor.java:2327)
    at com.sun.enterprise.deployment.EjbDescriptor.getLocalRemoteBusinessMethodDescriptors(EjbDescriptor.java:2290)
    ... 40 more

com.rares.test.Person

@Entity
@Table (name="PERSON")
public class Person implements Serializable {
    private static final long serialVersionUID = 3707476467775531463L;

    @Id
    @GeneratedValue (strategy=GenerationType.IDENTITY)
    @Column private Long id;
    @Column private String name;

com.rares.test.PersonManager

public interface PersonManager {
    void create (com.rares.test.Person p);
}

com.rares.test.PersonDao

@Stateless
public class PersonDao implements PersonManager {
    @PersistenceContext (unitName="RarePersistUnit")
    protected EntityManager mgr;

    @Override
    public void create(com.rares.test.Person p) {
        mgr.persist(p); 
    }

}

persistence.xml

<persistence version="2.0" 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_2_0.xsd">
    <persistence-unit name="RarePersistUnit">
        <provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
        <jta-data-source>jdbc/RaresMySql</jta-data-source>
        <class>com.rares.test.Person</class>        
        <properties>

        </properties>
    </persistence-unit>
</persistence>
like image 427
AR3Y35 Avatar asked Jul 17 '11 04:07

AR3Y35


1 Answers

Note: The below assumes OpenJPA 2.1 and Glassfish 3.1. Results may vary across versions of both.

The exception thrown is typical of a failure to perform bytecode enchancement at runtime by OpenJPA. Bytecode enhancement can be done at either build time or at runtime. One of the better options available to get runtime support is to use a javaagent but requires some kooky configuration in that:

  • it requires you to specify a javaagent in the Glassfish domain configuration file (by specifying an additional jvm-options element under the java-config element),
  • and also modify the classpath from the default value of ${com.sun.aas.installRoot}/modules/glassfish.jar to include commons-lang-2.4.jar (which I didn't bother doing, as it would have leady to a very fragile setup).

Other options that can be used at runtime are quite flaky, and the choice of using Serp as the bytecode enhancer is the cause of the exception thrown at deploy time. Apparently, the deploy time enhancement fails to locate the classes used in the persistence context, due to incorrect classloaders being used to locate the classes. In my case, the Glassfish EarClassLoader and EarLibClassLoader classloaders were used to load the classes in two separate invocations, with both failing with the following messages (the stack traces are immaterial here):

WARNING: LDR5207: ASURLClassLoader EarLibClassLoader : 
doneCalled = true
doneSnapshot = ASURLClassLoader.done() called ON EarLibClassLoader : 
urlSet = []
doneCalled = false 
 Parent -> org.glassfish.internal.api.DelegatingClassLoader@10e3c8c
 AT Sun Jul 17 13:27:54 IST 2011 
 BY :java.lang.Throwable: printStackTraceToString
    at com.sun.enterprise.util.Print.printStackTraceToString(Print.java:639)
    at com.sun.enterprise.loader.ASURLClassLoader.done(ASURLClassLoader.java:211)
    ...

...

WARNING: LDR5207: ASURLClassLoader EarClassLoader : 
doneCalled = true
doneSnapshot = ASURLClassLoader.done() called ON EarClassLoader : 
urlSet = [URLEntry : file:/C:/glassfish3/glassfish/domains/domain1/eclipseApps/app-ear/app-jsf-0.0.1-SNAPSHOT_war/WEB-INF/classes/, URLEntry : file:/C:/glassfish3/glassfish/domains/domain1/eclipseApps/app-ear/app-jsf-0.0.1-SNAPSHOT_war/WEB-INF/lib/commons-fileupload-1.2.1.jar, URLEntry : file:/C:/glassfish3/glassfish/domains/domain1/eclipseApps/app-ear/app-jsf-0.0.1-SNAPSHOT_war/WEB-INF/lib/commons-io-1.4.jar, URLEntry : file:/C:/glassfish3/glassfish/domains/domain1/eclipseApps/app-ear/app-jsf-0.0.1-SNAPSHOT_war/WEB-INF/lib/primefaces-3.0.M2.jar, URLEntry : file:/C:/glassfish3/glassfish/domains/domain1/generated/ejb/app-ear/app-jsf-0.0.1-SNAPSHOT_war/, URLEntry : file:/C:/glassfish3/glassfish/domains/domain1/eclipseApps/app-ear/app-ejb-0.0.1-SNAPSHOT_jar/, URLEntry : file:/C:/glassfish3/glassfish/domains/domain1/generated/ejb/app-ear/app-ejb-0.0.1-SNAPSHOT_jar]
doneCalled = false 
 Parent -> org.glassfish.internal.api.DelegatingClassLoader@1a3fe65
 AT Sun Jul 17 13:27:54 IST 2011 
 BY :java.lang.Throwable: printStackTraceToString
    at com.sun.enterprise.util.Print.printStackTraceToString(Print.java:639)
    at com.sun.enterprise.loader.ASURLClassLoader.done(ASURLClassLoader.java:211)
    ...

...

Apparently, for some unknown reason the generated classes area for EJBs did not contain the JPA entity classes at runtime, leading to the failure to locate the classes at deployment. The most possible reason for failure, is the fact that the entity classes although packaged within the EJB module, may themselves not have been placed in the generated classes directory; only the annotated EJB classes may have been placed there.

The only reasonable option is to therefore use build time enhancement, which was duly done using the following configuration in the Maven POM:

 <build>
     <plugins>
         <plugin>
             <groupId>org.apache.maven.plugins</groupId>
             <artifactId>maven-antrun-plugin</artifactId>
             <version>1.6</version>
                 <executions>
                     <execution>
                         <phase>process-classes</phase>
                         <configuration>
                             <tasks>
                                 <taskdef name="openjpac" classname="org.apache.openjpa.ant.PCEnhancerTask" classpathref="maven.compile.classpath"/>
                                 <openjpac>
                                     <classpath refid="maven.compile.classpath"/>
                                 </openjpac>
                             </tasks>
                         </configuration>
                         <goals>
                             <goal>run</goal>
                         </goals>
                     </execution>
                 </executions>
             </plugin>
         </plugins>
    </pluginManagement>
</build>

The above configuration was derived from the OpenJPA documentation on enhancing classes with Maven. Note that I did not use the openjpa-maven-plugin, as version 2.2.0 of OpenJPA is available only as a snapshot at the time of writing this.

Of course, any of the above also required installation of OpenJPA 2.1 in Glassfish 3.1, which was duly done by copying the following JARs to ${com.sun.aas.installRoot}/glassfish/lib (for instance, C:/glassfishv3/glassfish/lib), as opposed to the advice offered on the older blog posts of copying to ${com.sun.aas.instanceRoot}/lib (for instance, C:/glassfishv3/glassfish/domains/domain1/lib)

  • commons-beanutils-1.8.3.jar
  • commons-collections-3.2.1.jar
  • commons-dbcp-1.4.jar
  • commons-lang-2.4.jar
  • commons-logging-1.0.4.jar
  • commons-pool-1.5.4.jar
  • serp-1.13.1.jar
  • openjpa-2.1.0.jar

Apparently, placing these JARs in ${com.sun.aas.instanceRoot}/lib lead to a failure to deploy the application by the Maven Glassfish plugin.

The other JARs (geronimo-*, derby-* and org.apache.bval*) present in the OpenJPA 2.1 distribution are provided by Glassfish 3.1 as part of the Java EE 6 SDK, the Java DB implementation or the Derby client, and within the JSR 303 bean validation framework (Hibernate Validator).

like image 76
Vineet Reynolds Avatar answered Oct 14 '22 14:10

Vineet Reynolds