Simplifying JPA Testing with Springs PersistenceUnitPostProcessor

At my current client, we are writing an application that is deployed as an ear into Websphere. One of the goals of the project is to write out-of-container tests so that we dont have to build and deploy over and over again. Two of the tools we are using in this application is JPA for the ORM and Spring. Initially, we had two persistance.xml files, one for production and one for testing. Some of the differences were that the production version used a transaction type of JTA and the test version used resource local. There were a few other property differences, but otherwise they needed to be identical. At first this was ok, but as our list of classes and properties grew it became a maintenance hassle..

Object Partners

At my current client, we are writing an application that is deployed as an ear into Websphere. One of the goals of the project is to write out-of-container tests so that we don’t have to build and deploy over and over again. Two of the tools we are using in this application is JPA for the ORM and Spring. Initially, we had two persistance.xml files, one for production and one for testing. Some of the differences were that the production version used a transaction type of JTA and the test version used resource local. There were a few other property differences, but otherwise they needed to be identical. At first this was ok, but as our list of classes and properties grew it became a maintenance hassle.

At this point we wanted to find a way to only have one persistance.xml to use in both prod and testing. After some research we found Spring’s PersistenceUnitPostProcessor interface. Implementing this interface allows you to make changes to the persistence unit that is defined in persistence.xml. There is one method that looks like this:

public void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo pui);

The MutablePersistenceUnitInfo object that is passed in has all the information in persistence.xml in it and can be altered as needed. Here’s how we got it to work. Here’s how our production perstence.xml looks:

<?xml version="1.0"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0"
   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">  

   <persistence-unit name="oracleOpenJpa" transaction-type="JTA">
      <jta-data-source>jdbc/dS</jta-data-source>
      <non-jta-data-source>jdbc/dS-NO-JTA</non-jta-data-source>  

      <class>...</class>
      <exclude-unlisted-classes>true</exclude-unlisted-classes>  

      <properties>
         <property name="openjpa.ConnectionFactoryMode" value="managed" />
         <property name="openjpa.TransactionMode" value="managed" />
      </properties>  

   </persistence-unit>
</persistence>

Here is our implementation of the interface:

package org.acme.jpa;  

import java.util.Map;
import java.util.Properties;  

import javax.persistence.spi.PersistenceUnitTransactionType;
import javax.sql.DataSource;  

import org.apache.commons.lang.ObjectUtils;
import org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo;
import org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor;  

public class MyPersistenceUnitPostProcessor implements PersistenceUnitPostProcessor {  

   private String persistenceUnitName;
   private Properties persistenceProperties;
   private DataSource dataSource;  

   public MyPersistenceUnitPostProcessor(final String persistenceUnitName,
          final DataSource dataSource, final Properties persistenceProperties) {
      this.persistenceUnitName = persistenceUnitName;
      this.persistenceProperties = persistenceProperties;
      this.dataSource = dataSource;
   }  

   public void postProcessPersistenceUnitInfo(final MutablePersistenceUnitInfo pui) {
      if(ObjectUtils.equals(persistenceUnitName, pui.getPersistenceUnitName())) {
         pui.setJtaDataSource(null);
         pui.setNonJtaDataSource(dataSource);
         pui.setTransactionType(PersistenceUnitTransactionType.RESOURCE_LOCAL);
         pui.setPersistenceProviderClassName(
            "org.apache.openjpa.persistence.PersistenceProviderImpl");  

         final Properties properties = pui.getProperties();  

         for (final Map.Entry entries : persistenceProperties.entrySet()) {
            properties.put(entries.getKey(), entries.getValue());
         }
      }
   }  

}

And here’s the spring configuration:

<bean id="entityManagerFactory"
   class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
   <property name="persistenceUnitName" value="oracleOpenJpa" />
   <property name="dataSource" ref="oracleDataSource" />
   <property name="persistenceUnitPostProcessors">
      <list>
         <bean class="org.acme.jpa.MyPersistenceUnitPostProcessor">
            <constructor-arg value="oracleOpenJpa" />
            <constructor-arg ref="oracleDataSource" />
            <constructor-arg>
               <props>
                  <prop key="openjpa.ConnectionFactoryMode">local</prop>
                  <prop key="openjpa.TransactionMode">local</prop>
               </props>
            </constructor-arg>
         </bean>  

      </list>
   </property>
</bean>

As you can see in the implementation, we set the JTA datasource to null (we don’t use it for testing), and set the non-jta datasource to the one defined in Spring. We also set the transaction type to resource local, set the provider class name and add whatever properties we pass in. In our case we just set a couple properties to “local”. By using these tools, we are able to just keep one persistance.xml file for both production and for testing and the maintenance hassle is gone.

Share this Post

Related Blog Posts

JVM

Write Readable Tests with Mockito

December 4th, 2009

A good mocking framework is a must have in any Java developers toolset. Mocking frameworks greatly reduce the amount of code needed to effectively mock dependent interfaces and/or classes. Over the past several years EasyMock has been my mocking…

David Reines
JVM

Mac OS X Development Hurdles

November 23rd, 2009

Moving to Mac OS X as a development environment and some issues or differences discovered.

Object Partners
JVM

Default settings of svn:keywords property

October 28th, 2009

Keyword expansion is not the default for files added to an SVN repository.  And it’s done on a per file basis (with CVS we could configure an entire repository to turn on keyword expansion — .)  Some svn tools and plugins allow for defaulting…

Object Partners

About the author