Thursday 13 September 2012

Persistence.xml cheat sheet for Hibernate, EclipseLink and OpenJPA

<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="jta" transaction-type="JTA">
  <provider>org.hibernate.ejb.HibernatePersistence</provider>
  <jta-data-source>jdbc/myderby</jta-data-source>
 </persistence-unit>

 <persistence-unit name="hibernate-resourceLocal" transaction-type="RESOURCE_LOCAL">
  <provider>org.hibernate.ejb.HibernatePersistence</provider>
  <properties>
   <!-- Connection properties -->
   <property name="hibernate.connection.driver_class" value="org.apache.derby.jdbc.ClientDriver" />
   <property name="hibernate.connection.url" value="jdbc:derby://localhost:1527/c:\derbydb\mydb" />
   <property name="hibernate.connection.username" value="APP" />
   <property name="hibernate.connection.password" value="APP" />

   <property name="hibernate.dialect" value="org.hibernate.dialect.DerbyDialect" />
   <!-- create-drop, create -->
   <property name="hibernate.hbm2ddl.auto" value="update" />
   <property name="hibernate.show_sql" value="true" />
   <property name="hibernate.format_sql" value="true" />
   <property name="hibernate.connection.autocommit" value="true" />
  </properties>
 </persistence-unit>

 <persistence-unit name="eclipseLink-resourceLocal" transaction-type="RESOURCE_LOCAL">
  <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
  <class>com.test.entity.User</class>
  <properties>
   <!-- Connection properties -->
   <property name="eclipselink.jdbc.driver" value="org.apache.derby.jdbc.ClientDriver" />
   <property name="eclipselink.jdbc.url" value="jdbc:derby://localhost:1527/c:\derbydb\mydb" />
   <property name="eclipselink.jdbc.user" value="APP" />
   <property name="eclipselink.jdbc.password" value="APP" />

   <property name="eclipselink.target-database" value="Derby" />
   <!-- drop-and-create-tables -->
   <property name="eclipselink.ddl-generation" value="create-tables" />
   <property name="eclipselink.ddl-generation.output-mode"
    value="database" />
   <property name="eclipselink.logging.parameters" value="true" />
   <property name="eclipselink.logging.level" value="FINE" />
  </properties>
 </persistence-unit>

 <persistence-unit name="openjpa-resourceLocal" transaction-type="RESOURCE_LOCAL">
  <provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
  <class>com.test.entity.User</class>
  <properties>
   <!-- Connection properties -->
   <property name="openjpa.ConnectionDriverName" value="org.apache.derby.jdbc.ClientDriver" />
   <property name="openjpa.ConnectionURL" value="jdbc:derby://localhost:1527/c:\derbydb\mydb" />
   <property name="openjpa.ConnectionUserName" value="APP" />
   <property name="openjpa.ConnectionPassword" value="APP" />

   <property name="openjpa.RuntimeUnenhancedClasses" value="supported" />
   <property name="openjpa.jdbc.DBDictionary" value="derby" />
   <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)" />
   <property name="openjpa.Log" value="DefaultLevel=WARN, Runtime=INFO, Tool=INFO, SQL=TRACE" />
  </properties>
 </persistence-unit>
</persistence>

Use Hibernate as JPA provider in Glassfish

Glassfish's default JPA provider is EclipseLink. For some reason, I need to replace EclipseLink with Hibernate as the JPA provider.

This article describes the steps I take, the difficulties I come across and how I overcome them.

My development environment:

Eclipse 3.6.2 (oepe-helios-all-in-one)  downloaded from here.
Glassfish 3.1.2
Apache Derby Server

I begin by creating a ordinary Java project in eclipse, named 'jpa'

Create the persistence.xml file under META-INF folder, which is under src.








Since I am not quite sure whether I have configured the JNDI data source correctly (which is out of the scope of this article), I still use EclipseLink as the JPA provider for now. So here is the contents of persistence.xml.
















Then I create a simple entity bean (User) and a simple stateless session bean (UserManagerBean).

The final project structure should look like this:














I want to test the persistence configuration so eagerly that I immediately create an Enterprise Application Project called jpa-ear, add the jpa project into it, and try to deploy the ear into Glassfish server.

I get the following error unexpectedly. I would expect the console to tell me that the UserManagerBean was successfully deployed and ready to be looked up by JNDI, as such.

I remember having deployed a stateless session bean into JBoss successfully. At this stage, I am not sure whether there is something wrong with my data source configuration or the Glassfish requires a web project to be included in the EAR.



















Then I create a web project, called jpa-web,  and add it to the jpa-ear project. Interestingly, the EAR is deployed successfully even I haven't linked the web project to the ejb project.

The console says UserManagerBean has a JNDI name.






I write a servlet class to make sure the User can be persisted into the database. Now it is time I moved on to the central part of this task ----- replacing the EclipseLink with Hibernete.

I update the persistence.xml to the following:
















As soon as the file is saved, auto deployment kicks off, and an error message pops up.

















Fair enough. That is because Glassfish can't find the hibernate libraries.

I could copy the hibernate libraries into Glassfish's lib folder but I don't want to do that. Because I just want the hibernate persistence provider to be confined in this application scope and don't like the other applications to be affected at all.

So I download the latest hibernate release and add the necessary jar files to jpa project's classpath, only disappointed to see the error is still there.

I copy all the jar files to the lib folder in jpa-web project.  Buy it's still not working.

I then realize that it is the EAR that gets deployed to the server, not the WAR. So if any project needs these jar files, it should be the EAR project rather than the WEB project!

However, there is no lib folder under jpa-ear project. I right click the project, and select Deployment Assembly. There seem to have something I can try.



























I go Add -> Archives from File System -> Add, select all the necessary jar files





























This time it is complaining about another missing class.

















Obviously, the server has found the org.hibernate.ejb.HibernatePersistence class it was complaining about before. Now the org.hibernate.proxy.EntityNotFoundDelegate is missing.

With the help of jarfinder, I come to know that the hibernate-core jar file contains the EntityNotFoundDelegate class. But haven't I just added this class to the EAR project?

Checking out the Deployment Assembly window again, I notice something weird --- The hibernate-core jar file, along with two other jar files, does not have lib in its deploy path.

















Under jpa-web/EAR Libraries, those three jar files without lib in their path are not there!



















I don't know why those 3 jar files are not included in the EAR libraries. Is it a bug of Eclipse?

It looks like I need to change some configuration file to add lib to those 3 jar files' path. Luckily it doesn't take long to find the configuration file. It is named org.eclipse.wst.common.component under jpa-ear/.settings.

For hibernate-commons-annotations.jarjavassist.jarhibernate-core.jar, add lib in their deploy-path attribute. Here is the screenshot for hibernate-core.jar





Refresh the jpa-ear project, redeploy the ear to Glassfish. And it works fine.