14.6 JPA

Spring JPA (available under the org.springframework.orm.jpa package) offers comprehensive support for the Java Persistence API in a similar manner to the integration with Hibernate or JDO, while being aware of the underlying implementation in order to provide additional features.

14.6.1 JPA setup in a Spring environment

Spring JPA offers three ways of setting up JPA EntityManagerFactory:

14.6.1.1 LocalEntityManagerFactoryBean

The LocalEntityManagerFactoryBean creates an EntityManagerFactory suitable for environments which solely use JPA for data access. The factory bean will use the JPA PersistenceProvider autodetection mechanism (according to JPA's Java SE bootstrapping) and, in most cases, requires only the persistence unit name to be specified:

<beans>

   <bean id="myEmf" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
      <property name="persistenceUnitName" value="myPersistenceUnit"/>
   </bean>

</beans>

This is the simplest but also most limited form of JPA deployment. There is no way to link to an existing JDBC DataSource and no support for global transactions, for example. Furthermore, weaving (byte-code transformation) of persistent classes is provider-specific, often requiring a specific JVM agent to specified on startup. All in all, this option is only really sufficient for standalone applications and test environments (which is exactly what the JPA specification designed it for).

Only use this option in simple deployment environments like standalone applications and integration tests.

14.6.1.2 Obtaining an EntityManagerFactory from JNDI

Obtaining an EntityManagerFactory from JNDI (for example in a Java EE 5 environment), is just a matter of changing the XML configuration:

<beans>

    <jee:jndi-lookup id="myEmf" jndi-name="persistence/myPersistenceUnit"/>

</beans>

This assumes standard Java EE 5 bootstrapping, with the Java EE server autodetecting persistence units (i.e. META-INF/persistence.xml files in application jars) and persistence-unit-ref entries in the Java EE deployment descriptor (e.g. web.xml) defining environment naming context locations for those persistence units.

In such a scenario, the entire persistence unit deployment, including the weaving (byte-code transformation) of persistent classes, is up to the Java EE server. The JDBC DataSource is defined through a JNDI location in the META-INF/persistence.xml file; EntityManager transactions are integrated with the server's JTA subsystem. Spring merely uses the obtained EntityManagerFactory, passing it on to application objects via dependency injection, and managing transactions for it (typically through JtaTransactionManager).

Note that, in case of multiple persistence units used in the same application, the bean names of such a JNDI-retrieved persistence units should match the persistence unit names that the application uses to refer to them (e.g. in @PersistenceUnit and @PersistenceContext annotations).

Use this option when deploying to a Java EE 5 server. Check your server's documentation on how to deploy a custom JPA provider into your server, allowing for a different provider than the server's default.

14.6.1.3 LocalContainerEntityManagerFactoryBean

The LocalContainerEntityManagerFactoryBean gives full control over EntityManagerFactory configuration and is appropriate for environments where fine-grained customization is required. The LocalContainerEntityManagerFactoryBean will create a PersistenceUnitInfo based on the persistence.xml file, the supplied dataSourceLookup strategy and the specified loadTimeWeaver. It is thus possible to work with custom DataSources outside of JNDI and to control the weaving process.

<beans>
        
 <bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="dataSource" ref="someDataSource"/>
  <property name="loadTimeWeaver">
    <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
  </property>
 </bean>
 
</beans>

A typical persistence.xml file looks as follows:

<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">

  <persistence-unit name="myUnit" transaction-type="RESOURCE_LOCAL">
    <mapping-file>META-INF/orm.xml</mapping-file>
    <exclude-unlisted-classes/>
  </persistence-unit>

</persistence>

NOTE: The "exclude-unlisted-classes" element always indicates that NO scanning for annotated entity classes is supposed to happen, in order to support the <exclude-unlisted-classes/> shortcut. This is in line with the JPA specification (which suggests that shortcut) but unfortunately in conflict with the JPA XSD (which implies "false" for that shortcut). As a consequence, "<exclude-unlisted-classes> false </exclude-unlisted-classes/>" is not supported! Simply omit the "exclude-unlisted-classes" element if you would like entity class scanning to actually happen.

This is the most powerful JPA setup option, allowing for flexible local configuration within the application. It supports links to an existing JDBC DataSource, supports both local and global transactions, etc. However, it also imposes requirements onto the runtime environment, such as the availability of a weaving-capable ClassLoader if the persistence provider demands byte-code transformation.

Note that this option may conflict with the built-in JPA capabilities of a Java EE 5 server. So when running in a full Java EE 5 environment, consider obtaining your EntityManagerFactory from JNDI. Alternatively, specify a custom "persistenceXmlLocation" on your LocalContainerEntityManagerFactoryBean definition, e.g. "META-INF/my-persistence.xml", and only include a descriptor with that name in your application jar files. Since the Java EE 5 server will only look for default META-INF/persistence.xml files, it will ignore such custom persistence units and hence avoid conflicts with a Spring-driven JPA setup upfront. (This applies to Resin 3.1, for example.)

Use this option for full JPA capabilities in a Spring-based application environment. This includes web containers such as Tomcat as well as standalone applications and integration tests with sophisticated persistence requirements.

The LoadTimeWeaver interface is a Spring-provided class that allows JPA ClassTransformer instances to be plugged in a specific manner depending on the environment (web container/application server). Hooking ClassTransformers through a Java 5 agent is typically not efficient - the agents work against the entire virtual machine and inspect every class that is loaded - something that is typically undesirable in a production server enviroment.

Spring provides a number of LoadTimeWeaver implementations for various environments, allowing ClassTransformer instances to be applied only per ClassLoader and not per VM.

The following sections will discuss typical JPA weaving setup on Tomcat as well as using Spring's VM agent. See the AOP chapter section entitled Section 8.8.4.5, “Spring configuration” for details on how to set up general load-time weaving, covering Tomcat and the VM agent as well as WebLogic, OC4J, GlassFish and Resin.

Tomcat load-time weaving setup (5.0+)

Apache Tomcat's default ClassLoader does not support class transformation but allows custom ClassLoaders to be used. Spring offers the TomcatInstrumentableClassLoader (inside the org.springframework.instrument.classloading.tomcat package) which extends the Tomcat ClassLoader (WebappClassLoader) and allows JPA ClassTransformer instances to 'enhance' all classes loaded by it. In short, JPA transformers will be applied only inside a specific web application (which uses the TomcatInstrumentableClassLoader).

In order to use the custom ClassLoader on:

  1. Copy spring-tomcat-weaver.jar into $CATALINA_HOME/server/lib (where $CATALINA_HOME represents the root of the Tomcat installation).

  2. Instruct Tomcat to use the custom ClassLoader (instead of the default one) by editing the web application context file:

    <Context path="/myWebApp" docBase="/my/webApp/location">
        <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/>
    </Context>

    Tomcat 5.0.x and 5.5.x series support several context locations: server configuration file ($CATALINA_HOME/conf/server.xml), the default context configuration ($CATALINA_HOME/conf/context.xml) that affects all deployed web applications and per-webapp configurations, deployed on the server ($CATALINA_HOME/conf/[enginename]/[hostname]/my-webapp-context.xml) side or along with the webapp (your-webapp.war/META-INF/context.xml). For efficiency, inside the web-app configuration style is recommended since only applications which use JPA will use the custom ClassLoader. See the Tomcat 5.x documentation for more details about available context locations.

    Note that versions prior to 5.5.20 contained a bug in the XML configuration parsing preventing usage of Loader tag inside server.xml (no matter if a ClassLoader is specified or not (be it the official or a custom one). See Tomcat's bugzilla for more details.

    If you are using Tomcat 5.5.20+ you can set useSystemClassLoaderAsParent to false to fix the problem:

    <Context path="/myWebApp" docBase="/my/webApp/location">
        <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"
                useSystemClassLoaderAsParent="false"/>
    </Context>
  1. Copy spring-tomcat-weaver.jar into $CATALINA_HOME/lib (where $CATALINA_HOME represents the root of the Tomcat installation).

  2. Instruct Tomcat to use the custom ClassLoader (instead of the default one) by editing the web application context file:

    <Context path="/myWebApp" docBase="/my/webApp/location">
        <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/>
    </Context>

    Tomcat 6.0.x (similar to 5.0.x/5.5.x) series support several context locations: server configuration file ($CATALINA_HOME/conf/server.xml), the default context configuration ($CATALINA_HOME/conf/context.xml) that affects all deployed web applications and per-webapp configurations, deployed on the server ($CATALINA_HOME/conf/[enginename]/[hostname]/my-webapp-context.xml) side or along with the webapp (your-webapp.war/META-INF/context.xml). For efficiency, inside the web-app configuration style is recommended since only applications which use JPA will use the custom ClassLoader. See the Tomcat 5.x documentation for more details about available context locations.

  • Tomcat 5.0.x/5.5.x

  • Tomcat 6.0.x

The last step required on all Tomcat versions, is to use the appropriate the LoadTimeWeaver when configuring LocalContainerEntityManagerFactoryBean:

<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="loadTimeWeaver">
    <bean class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver"/>
  </property>
</bean>

Using this technique, JPA applications relying on instrumentation, can run in Tomcat without the need of an agent. This is important especially when hosting applications which rely on different JPA implementations since the JPA transformers are applied only at ClassLoader level and thus, are isolated from each other.

[Note]Note

If TopLink is being used a JPA provider under Tomcat, please place the toplink-essentials jar under $CATALINA_HOME/shared/lib folder instead of your war.

General load-time weaving using the VM agent

For environments where class instrumentation is required but are not supported by the existing LoadTimeWeaver implementations, a JDK agent can be the only solution. For such cases, Spring provides InstrumentationLoadTimeWeaver which requires a Spring-specific (but very general) VM agent (spring-agent.jar):

<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="loadTimeWeaver">
    <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
  </property>
</bean>

Note that the virtual machine has to be started with the Spring agent, by supplying the following JVM options:

-javaagent:/path/to/spring-agent.jar
Context-wide load-time weaver setup

Since Spring 2.5, a context-wide LoadTimeWeaver can be configured using the context:load-time-weaver configuration element. Such a 'global' weaver will be picked up by all JPA LocalContainerEntityManagerFactoryBeans automatically.

This is the preferred way of setting up a load-time weaver, delivering autodetection of the platform (WebLogic, OC4J, GlassFish, Tomcat, Resin, VM agent) as well as automatic propagation of the weaver to all weaver-aware beans.

<context:load-time-weaver/>

<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    ...
</bean>

See the section entitled Section 8.8.4.5, “Spring configuration” for details on how to set up general load-time weaving, covering Tomcat and the VM agent as well as WebLogic, OC4J, GlassFish and Resin.

14.6.1.4 Dealing with multiple persistence units

For applications that rely on multiple persistence units locations (stored in various jars in the classpath for example), Spring offers the PersistenceUnitManager to act as a central repository and avoid the (potentially expensive) persistence units discovery process. The default implementation allows multiple locations to be specified (by default, the classpath is searched for 'META-INF/persistence.xml' files) which are parsed and later on retrieved through the persistence unit name:

<bean id="pum" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
  <property name="persistenceXmlLocation">
    <list>
     <value>org/springframework/orm/jpa/domain/persistence-multi.xml</value>
     <value>classpath:/my/package/**/custom-persistence.xml</value>
     <value>classpath*:META-INF/persistence.xml</value>
    </list>
  </property>
  <property name="dataSources">
   <map>
    <entry key="localDataSource" value-ref="local-db"/>
    <entry key="remoteDataSource" value-ref="remote-db"/>
   </map>
  </property>
  <!-- if no datasource is specified, use this one -->
  <property name="defaultDataSource" ref="remoteDataSource"/>
</bean>

<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="persistenceUnitManager" ref="pum"/>
</bean>

Note that the default implementation allows customization of the persistence unit infos before feeding them to the JPA provider declaratively through its properties (which affect all hosted units) or programmatically, through the PersistenceUnitPostProcessor (which allows persistence unit selection). If no PersistenceUnitManager is specified, one will be created and used internally by LocalContainerEntityManagerFactoryBean.

14.6.2 JpaTemplate and JpaDaoSupport

Each JPA-based DAO will then receive a EntityManagerFactory via dependency injection. Such a DAO can be coded against plain JPA and work with the given EntityManagerFactory or through Spring's JpaTemplate:

<beans>

  <bean id="myProductDao" class="product.ProductDaoImpl">
    <property name="entityManagerFactory" ref="myEmf"/>
  </bean>

</beans>
public class JpaProductDao implements ProductDao {
  
    private JpaTemplate jpaTemplate;

    public void setEntityManagerFactory(EntityManagerFactory emf) {
        this.jpaTemplate = new JpaTemplate(emf);
    }

    public Collection loadProductsByCategory(final String category) throws DataAccessException {
        return (Collection) this.jpaTemplate.execute(new JpaCallback() {
            public Object doInJpa(EntityManager em) throws PersistenceException {
                Query query = em.createQuery("from Product as p where p.category = :category");
                query.setParameter("category", category);
                List result = query.getResultList(); 
                // do some further processing with the result list
                return result;
            }
        });
    }
}

The JpaCallback implementation allows any type of JPA data access. The JpaTemplate will ensure that EntityManagers are properly opened and closed and automatically participate in transactions. Moreover, the JpaTemplate properly handles exceptions, making sure resources are cleaned up and the appropriate transactions rolled back. The template instances are thread-safe and reusable and they can be kept as instance variable of the enclosing class. Note that JpaTemplate offers single-step actions such as find, load, merge, etc along with alternative convenience methods that can replace one line callback implementations.

Furthermore, Spring provides a convenient JpaDaoSupport base class that provides the get/setEntityManagerFactory and getJpaTemplate() to be used by subclasses:

public class ProductDaoImpl extends JpaDaoSupport implements ProductDao {
  
    public Collection loadProductsByCategory(String category) throws DataAccessException {
        Map<String, String> params = new HashMap<String, String>();
        params.put("category", category);
        return getJpaTemplate().findByNamedParams("from Product as p where p.category = :category", params);
    }
}

Besides working with Spring's JpaTemplate, one can also code Spring-based DAOs against the JPA, doing one's own explicit EntityManager handling. As also elaborated in the corresponding Hibernate section, the main advantage of this approach is that your data access code is able to throw checked exceptions. JpaDaoSupport offers a variety of support methods for this scenario, for retrieving and releasing a transaction EntityManager, as well as for converting exceptions.

JpaTemplate mainly exists as a sibling of JdoTemplate and HibernateTemplate, offering the same style for people used to it. For newly started projects, consider adopting the native JPA style of coding data access objects instead, based on a "shared EntityManager" reference obtained through the JPA @PersistenceContext annotation (using Spring's PersistenceAnnotationBeanPostProcessor; see below for details.)

14.6.3 Implementing DAOs based on plain JPA

[Note]Note

While EntityManagerFactory instances are thread-safe, EntityManager instances are not. The injected JPA EntityManager behave just like an EntityManager fetched from an application server's JNDI environment, as defined by the JPA specification. It will delegate all calls to the current transactional EntityManager, if any; else, it will fall back to a newly created EntityManager per operation, making it thread-safe.

It is possible to write code against the plain JPA without using any Spring dependencies, using an injected EntityManagerFactory or EntityManager. Note that Spring can understand @PersistenceUnit and @PersistenceContext annotations both at field and method level if a PersistenceAnnotationBeanPostProcessor is enabled. A corresponding DAO implementation might look like this:

public class ProductDaoImpl implements ProductDao {

    private EntityManagerFactory emf;

    @PersistenceUnit
    public void setEntityManagerFactory(EntityManagerFactory emf) {
        this.emf = emf;
    }

    public Collection loadProductsByCategory(String category) {
        EntityManager em = this.emf.createEntityManager();
        try {
             Query query = em.createQuery("from Product as p where p.category = ?1");
             query.setParameter(1, category);
             return query.getResultList();
        }
        finally {
            if (em != null) {
                em.close();
            }
        }
    }
}

The DAO above has no dependency on Spring and still fits nicely into a Spring application context, just like it would if coded against Spring's JpaTemplate. Moreover, the DAO takes advantage of annotations to require the injection of the default EntityManagerFactory:

<beans>

  <!-- bean post-processor for JPA annotations -->
  <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>

  <bean id="myProductDao" class="product.ProductDaoImpl"/>

</beans>

Note: As alternative to defining a PersistenceAnnotationBeanPostProcessor explicitly, consider using Spring 2.5's context:annotation-config XML element in your application context configuration. This will automatically register all of Spring's standard post-processors for annotation-based configuration (including CommonAnnotationBeanPostProcessor etc).

<beans>

  <!-- post-processors for all standard config annotations -->
  <context:annotation-config/>

  <bean id="myProductDao" class="product.ProductDaoImpl"/>

</beans>

The main issue with such a DAO is that it always creates a new EntityManager via the factory. This can be easily overcome by requesting a transactional EntityManager (also called "shared EntityManager", since it is a shared, thread-safe proxy for the actual transactional EntityManager) to be injected instead of the factory:

public class ProductDaoImpl implements ProductDao {

    @PersistenceContext
    private EntityManager em;

    public Collection loadProductsByCategory(String category) {
       Query query = em.createQuery("from Product as p where p.category = :category");
       query.setParameter("category", category);
       return query.getResultList(); 
    }
}

Note that the @PersistenceContext annotation has an optional attribute type, which defaults to PersistenceContextType.TRANSACTION. This default is what you need to receive a "shared EntityManager" proxy. The alternative, PersistenceContextType.EXTENDED, is a completely different affair: This results in a so-called "extended EntityManager", which is not thread-safe and hence must not be used in a concurrently accessed component such as a Spring-managed singleton bean. Extended EntityManagers are only supposed to be used in stateful components that, for example, reside in a session, with the lifecycle of the EntityManager not tied to a current transaction but rather being completely up to the application.

The injected EntityManager is Spring-managed (aware of the ongoing transaction). It is important to note that even though the new implementation prefers method level injection (of an EntityManager instead of an EntityManagerFactory), no change is required in the application context XML due to annotation usage.

The main advantage of this DAO style is that it depends on Java Persistence API; no import of any Spring class is required. Moreover, as the JPA annotations are understood, the injections are applied automatically by the Spring container. This is of course appealing from a non-invasiveness perspective, and might feel more natural to JPA developers.

14.6.4 Exception Translation

However, the DAO throws the plain PersistenceException exception class (which is unchecked, and so does not have to be declared or caught) but also IllegalArgumentException and IllegalStateException, which means that callers can only treat exceptions as generally fatal - unless they want to depend on JPA's own exception structure. Catching specific causes such as an optimistic locking failure is not possible without tying the caller to the implementation strategy. This tradeoff might be acceptable to applications that are strongly JPA-based and/or do not need any special exception treatment. However, Spring offers a solution allowing exception translation to be applied transparently through the @Repository annotation:

@Repository
public class ProductDaoImpl implements ProductDao {

    // class body here...

}
<beans>

  <!-- Exception translation bean post processor -->
  <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>

  <bean id="myProductDao" class="product.ProductDaoImpl"/>

</beans>

The postprocessor will automatically look for all exception translators (implementations of the PersistenceExceptionTranslator interface) and advise all beans marked with the @Repository annotation so that the discovered translators can intercept and apply the appropriate translation on the thrown exceptions.

In summary: DAOs can be implemented based on the plain Java Persistence API and annotations, while still being able to benefit from Spring-managed transactions, dependency injection, and transparent exception conversion (if desired) to Spring's custom exception hierarchies.