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.private开发者_如何学CGetPublicMethods(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>
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 additionaljvm-options
element under thejava-config
element), - and also modify the classpath from the default value of
${com.sun.aas.installRoot}/modules/glassfish.jar
to includecommons-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).
精彩评论