Chapter 4. Spring JPA

When comes to ORM frameworks, plenty of frameworks exist. We have already seen Hibernate in our last chapter. Frameworks may have a free hand when it comes to implementation if no standard is around. A standard or a specification helps the end user in swapping the frameworks without much hassle should the need arise. Java folks realised the need of a persistence standard that would help the user community. The standard is called a Java Persistence API (JPA)—an API that helps to standardize the Java Persistence world.

In this chapter, we will look at the Java Persistence API at a high level and at Spring’s support to use the API with few providers, especially with the Hibernate provider. As expected, there will be a few players who implement the specification and bring the standard to life. We see discuss one such provider—Hibernate itself—in this chapter.

Two-Minute JPA

The JPA defines an EntityManager interface, which is basically the heart of the API. It is similar to Hibernate’s Session, forming the core of the application to perform database operations.

As you create Session from a SessionFactory, it’s not hard to understand that you use EntityManagerFactory to create an instance of EntityManager. However, because JPA is a standard applicable to Enterprise and Standalone applications, there are a couple of modes for obtaining or creating the EntityManagerFactory itself—one that will be created in a managed environment such as Application Servers or Web containers while the other in a standalone application.

Once you have the EntityManager (obtained from EntityManagerFactory), the next step is to declare a persistence unit. A persistence unit is a logical group of persistent classes (called entities in JPA lingo), database settings, and relational mappings.

We will see the EntityManager and its factory in action in a few pages, but for now, let’s look at the following snippet that indicates a persistence-unit:

<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_2_0.xsd"
  version="2.0">

  <persistence-unit name="trade-mysql-pu" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <class>com.madhusudhan.jsd.domain.jpa.Trade</class>
    <properties>
      <property name="hibernate.connection.url" 
        value="jdbc:mysql://localhost:3306/JSDATA"/>
      <property name="hibernate.connection.driver_class" 
        value="com.mysql.jdbc.Driver"/>
      <property name="hibernate.dialect" 
        value="org.hibernate.dialect.MySQL5Dialect"/>
      ...
    </properties>
  </persistence-unit>
</persistence>

As you can see, a persistent-unit named trade-mysql-pu was created with a single persistent entity (Trade) and the HibernatePersistence as the provider (the implementor of the JPA Specification). The properties indicate the settings of the database which are similar to the DataSource definition properties.

One norm you should follow is to create the persistence.xml file under a folder named META-INF. The providers are required to look for this file under that folder. If the folder doesn’t exist, create one and add it to the classpath.

The class attribute defines the persistent entity as seen in the above XML file. We create an entity with appropriate annotations (@Entity, @Column, @Id, and so on).

See below for an example of how the Trade entity is defined:

@Entity
@Table(name="TRADES")
public class Trade {
  @Column( nullable=false)
  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  private int id = 0;
  
  @Column
  private String direction = null;
  
  @Column
  private String account = null;

  ...

The entity annotation describes that this POJO is a persistable entity (a domain object) which maps to the TRADES table. You do not have to provide the table details if the class name matches to the table name (in our case, the domain object is Trade which doesn’t match to table TRADES). The properties follow the same path—they match to the column names.

The last thing to understand, which is covered in the next few pages, is how EntityManagerFactory’s and EntityManager’s are created.

The JPA specification classifies two types of entity managers: one that runs in a container-managed environment, and another that runs in a standalone JVM. The former one is typically a Java Enterprise Edition (JEE) container such as an application server or a web container, while the latter is a Java Standard Edition standalone program.

The EntityManager itself is no different in both types but the EntityManagerFactory that creates the EntityManager is a bit unique in how it is configured and created.

In a standalone environment, you should create the EntityManager as shown here:

private EntityManagerFactory factory = null;
private EntityManager entityManager = null;
..
private void init() {
  factory = Persistence.createEntityManagerFactory("trade-mysql-pu");
  entityManager = factory.createEntityManager();
}

You should pass in the name of the previously defined persistence unit (from persistence.xml) to the createEntityManagerFactory() method. We then obtain the EntityManager by calling createEntityManager on the factory.

In a container-managed environment, the class with a reference to the entity manager (typically DAO objects) will be injected with an existing EntityManager. The responsibility of looking up the persistence unit, creating the factory, and subsequently creating and injecting the EntityManager are all taken care of by the JEE application container.

Note that, however you get the EntityManager, whether from a JEE container or in a standalone mode, the operations on it are always the same. The fundamental difference involves its creation—not its workings.

Using Spring

What’s the value input from Spring in supporting JPA, you might ask?

The Spring framework supports the JPA API in couple of ways, very similar to support for Hibernate. One way is by providing the classic template: a JpaTemplate class. This class is basically a wrapper around the EntityManager similar to other templates such as HibernateTemplate.

The second way is by allowing the developer to use plain JPA API in the applications via an injected EntityManager class. If you are confused as to what approach to take, go with using plain API if possible. This way, Spring will be used solely for dependency injection thus avoiding any dependencies on its framework classes. Should you have earlier versions (before 3.x), perhaps sticking to template style might be easier.

Let’s explore both of these use cases in detail.

Basically, Spring encapsulates the EntityManagerFactory in its own FactoryBean implementation and injects them into the applications where it is needed.

Spring uses two implementations of FactoryBean for providing the EntityManagers in respective environments:

org.springframework.orm.jpa.LocalEntityManagerFactoryBean

This FactoryBean creates the EntityManagerFactory for standalone environments. This implementation provides a simple factory that has limitations. It cannot participate in global transactions, cannot work with DataSources.

org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean

This factory bean provides the EntityManagerFactory for enterprise environments. Note how its classname has the word “Container” embedded in it, compared to the previous LocalEntityManagerFactoryBean class.

We will see both of them in action in the next section.

Standalone Factory

In order to provide the EntityManager to your standalone Spring application, what we need to do is to define the LocalEntityManagerFactoryBean in your configuration file, as shown in the following snippet:

<bean id="entityManagerFactory"
  class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
  <property name="persistenceUnitName" value="trade-mysql-pu" />
</bean>

Note that the persistenceUnitName refers to the persitence-unit name provided in the persistence.xml file. The bean is now configured and ready to be injected. The following snippet shows how it has been injected into our TradeDAO object:

<bean id="entityManagerFactory" ..

<bean id="tradeDAO" class="com.madhusudhan.jsd.jpa.TradeDAO">
  <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

As expected, the factory will be injected into TradeDAO and it’s the TradeDAO’s job to create the EntityManager from the factory. This is shown in the following snippet:

private EntityManagerFactory entityManagerFactory = null;
private EntityManager manager = null;

public TradeDAO() {
  manager = getEntityManagerFactory().createEntityManager();
}

//setters for EntityManagerFactory - will be injected by Spring
public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) {
  this.entityManagerFactory = entityManagerFactory;
}

public EntityManagerFactory getEntityManagerFactory() {
  return entityManagerFactory;
}

Now that we have created the EntityManager instance, our job is done. We can use its contract API to execute data access operations such as creating, finding, and deleting entities, as well as many more operations against a database.

I’ve created few methods on the TradeDAO shown below:

public class TradeDAO {

  private EntityManagerFactory entityManagerFactory = null;
  private EntityManager manager = null;

  void persist(Trade t){
    // persist the object
    getManager().persist(t);
  }
  
  public void delete(Trade t){
    // delete the row
    getManager().remove(t);
  }
  ...
}

In order to insert a Trade object, we use the persist() method exposed on the EntityManager. Obviously, we need to start a transaction before we execute any data access operation and commit the transaction. Similarly, there are a few other methods such as merge, remove, and find to do relevant operations. Please refer to the standard API documentation for more details on using these methods beyond the examples shown here.

Container Factory

It is time to see how Spring provides a managed entity factory. In this situation, Spring acts as a container itself and all configuration is managed in its context file. As we learned earlier, the EntityManagerFactory is encapsulated by LocalContainerEntityManagerFactoryBean, which is recommended for most of the applications, including those meant to be used as standalone programs. This factory provides support for global and local transactions while utilizing the existing DataSource definitions.

Let’s see how we create the EntityManagerFactory via the Spring container.

Configuring the Factory

The following snippet shows the configuration required for creating the factory:

<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  
  <property name="dataSource" ref="mySqlDataSource" />
  <property name="packagesToScan" value="com.madhusudhan.jsd.jpa" />
  
  <property name="jpaVendorAdapter">
   <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
    <property name="showSql" value="true" />
    <property name="generateDdl" value="true" />
    <property name="databasePlatform" 
      value="org.hibernate.dialect.MySQL5Dialect" />
  </bean>
  </property>
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
  <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

<bean id="mySqlDataSource" class="org.apache.commons.dbcp.BasicDataSource">
  ...
</bean>

There are few interesting properties that deserve mentioning:

The dataSource property refers to the standard JDBC DataSource that is configured in the same XML file as we did before (shown as Apache Common’s DBCP DataSource in the snippet).

  • The factory class points to the framework’s LocalContainerEntityManagerFactoryBean class.

  • The pacakagesToScan attribute instructs the framework to browse through the relevant package ( com.madhusudhan.jsd.jpa in this case) to find the persistent entities by looking at the @Entity annotations on the class.

  • The jpaVendorAdapter attributes tells the bean to use Hibernate’s persistence provider. You may provide additional properties to the adapter such as generateDdl, databasePlatform (Dialect), batchSize, and so on.

Now that all the moving pieces are, or have been assembled, invoke the data access methods on TradeDAO. Because of all the changes we made previously were config related, there wouldn’t be any changes to the DAO object. Hence you can re-use the same TradeDAO:

public class TradeDAO {  
  ...
  public void persist(Trade t){
    // persist the object
    getManager().persist(t);
  }
  
  public void delete(Trade t){
    // delete the row
    getManager().remove(t);
  }
  ...
}

Use the DAO to execute relevant data access functions. Inserting a new Trade would be extraordinarily simple, as demonstrated here:

public class TradePersistorTest {
  ...
  public TradePersistorTest() {
    ctx = new ClassPathXmlApplicationContext("jpa-beans.xml");
    dao = ctx.getBean("tradeDao",TradeDAO.class);
  }
  public void persist(Trade p){
    dao.persist(p);
  }
  
  public static void main(String[] args) {
    TradePersistorTest test = new TradePersistorTest();
    Trade t = new Trade();
    //..set values on Trade t
    test.persist(t);
  }
}

As you can see, once you get the DAO bean from the container, invoke the persist operation to store a new Trade.

Transactions

The above methods must be executed in a transaction. If you are using programmatic demarcation of transactions, perhaps each of your data access operation should begin with a new transaction and end the transaction when done. Of course, you can span your transaction across multiple operations.

The EntityManager exposes methods to begin, commit, and/or rollback transactions. For example, the following snippet shows utility methods that create a new transaction and commit an existing transaction:

//beginning your transaction
private void begin() {
  getManager().getTransaction().begin();
}

//committing your transaction
private void commit() {
  getManager().getTransaction().commit();
}

In our DAO, we should demarcate the transactional boundaries as shown below:

public void persist(Trade p){
 
    // begin your tx
    begin(); //calls the above begin method
    
    // do your job
    dao.persist(p);
    
    // end your transaction
    commit();// calls the above commit method 
}

Spring also provides declarative transactional support. Please refer to section on declarative transactions discussed in Chapter 3.

Using Plain JPA API

While we can mix and match the framework’s elements into our data access layer, the recommended approach is to use the plain JPA API to execute data access operations. Spring’s support is excellent in achieving this goal, as we will see in few minutes.

The DAO’s setEntityManagerFactory method should be annotated with @PersistenceUnit annotation. Spring understands this annotation and accordingly will inject EntityManagerFactory into the DAO.

See the reworked example DAO using @PersistenceUnit annotation:

public class TradeDAO {

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

Did you notice that there are no Spring classes in the above DAO? The @PersistenceUnit annotation belongs to the JPA specification, which makes our DAO fully JPA-compliant. However, how does Spring know that it has to inject an EntityManagerFactory when the method is annotated with @PersistenceUnit annotation?

Well, it turns out that the magic is performed by Spring’s post processor bean: PersistenceAnnotationBeanPostProcessor. This bean is wired into your configuration XML, as shown below:

<!-- Reads the annotations -->
<bean
   class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

<bean id="tradeDao" class="com.madhusudhan.jpa.plain.TradeDAO"/>

<bean id="entityManagerFactory"
  class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">

  <property name="persistenceUnitName" value="trade-mysql-pu" />
</bean>

The rest of the beans in the XML configuration file are self-explanatory. If you wish to eliminate declaring individual post processors as shown above, you can use the following snippet that scans all of the post processors:

<context:annotation-config/>

Now that you have all the ammunition you need, all you have to do is to execute the functionality on the DAO via your test classes.

public class TradePersistorPlainJpaTest {

  public TradePersistorPlainJpaTest() {
    
    ctx = new ClassPathXmlApplicationContext("jpa-plain-beans.xml");
    
    dao = ctx.getBean("tradeDao",TradeDAO.class);
  }
  
  public void persist(Trade p){
    dao.persist(p);
  }
 ...
}

That’s about it!

We explore the Spring’s template support in the next section.

Using JpaTemplate

The JpaTemplate follows the same template pattern that we have observed all along in the Spring’s framework. It encapsulates the nitty-gritty of EntityManager and EntityManagerFactory implementations.

Note

The JpaTemplate has been deprecated since Spring version 3.1.x. It is strongly advised to use JPA API rather than JpaTemplate if you are using or migrating to version 3.1.x.

Define a bean named jpaTemplate and wire it with an EntityManagerFactory. This is shown below:

<bean id="jpaTemplate" class="org.springframework.orm.jpa.JpaTemplate">
  <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

Note that the entityManagerFactory is created from the pre-defined persistence-unit (unlike ContainerManagerFactory where the persistence unit definition is not required).

You do not need to change your definition of DAO.

Both are shown in the following snippet:

<!-- Using JPATemplate -->
<bean id="entityManagerFactory"
  class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
  <property name="persistenceUnitName" value="trade-mysql-pu" />
</bean>

<bean id="tradeDao" class="com.madhusudhan.jpa.TradeDAO">
  <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

<bean id="jpaTemplate".../>

The TradeDAO is :

public class TradeDAO {
  private JpaTemplate jpaTemplate = null;

  public void persist(Trade t){
    getJpaTemplate().persist(t);
  }

  //setter and getter for jpaTemplate
  ...
}

Now that you have the DAO, fetch it via your application context and invoke the appropriate methods.

public class TradePersistorJpaTemplateTest {

  public TradePersistorJpaTemplateTest() {
    ctx = new ClassPathXmlApplicationContext("jpa-beans.xml");
    dao = ctx.getBean("tradeDao",TradeDAO.class);
  }
  
  public void persist(Trade p){
    dao.persist(p);
  }
 ...
}

Note that JpaTemplate introduces another layer on top of your DAO layer, which is not really necessary.

Support Classes

As usual, Spring provides its XXXSupport classes for our convenience. All you have to do is to let your DAO class extend the framework’s JpaDaoSupport class. It then will have a reference to JpaTemplate.

The DAO class should look like this:

public class JPAPriceDAOSupport extends JpaDaoSupport {
  public void persist(Trade t) {
    getJpaTemplate().persist(t);
  }
}

Because you have extended the JpaDaoSupport class, the JpaTemplate will be readily available to your DAO instance. As you can see, the getJpaTemplate() will return the template object which is then used to invoke the appropriate data access operations.

The wiring of the DAO bean is shown below, which gets a EntityManagerFactory instance:

<bean id="jpaPriceDAOSupport" class="com.madhusudhan.jsd.jpa.support.JPAPriceDAOSupport">
  <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

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

Internally, the support class relies on JpaTemplate to do the actual work.

Note that the JpaDaoSupport class is deprecated in Spring version 3.1 or later. This way, Spring folks strongly encourage you to move on to using Spring with plain JPA API.

Summary

In this chapter, we looked at the Java Persistence API (JPA) from a very high level. We then tried to understand the Spring’s support in bringing the JPA into our Java application world. We learned about the EntityManagerFactory and EntityManager which form the basis to understanding the JPA solutions. We also looked at standalone versus managed environments, and ways to create the factories and instantiate the EntityManagers in these environments. We created our examples using plain JPA API and framework-dependent templates and support classes.

Get Just Spring Data Access now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.