Hibernate and JPA with Spring Example

The Java Persistence API (JPA) is a POJO persistence API for object/relational mapping. It contains a full object/relational mapping specification supporting the use of Java language metadata annotations and/or XML descriptors to define the mapping between Java objects and a relational database.


Here I’ll present an example of using standard JPA annotations to markup a set of POJOs and then persist the POJOs by configuring Spring to use the Hibernate AnnotationSessionFactoryBean. This example does not use the JPA API to work with persisted objects, rather, JPA annotations are only used to define the ORM mappings. Using these unaltered POJOs using the JPA API would 100% work and would almost be trivial.

For this example, I am going to use the domain of music albums. In a nutshell, there are Records that have an ordered list of Tracks as well as an Artist who created the Record. I will assume that this is a green-field project and we get to define the database schema (oh if life were always so simple :) ). I’ll assume that the use cases for this application are all Record-centric.

So I’ll start with the Record class. Here it is:

import java.io.Serializable;
import javax.persistence.Entity;

@Entity
public class Record implements Serializable
{
  private Integer id;
  private String title;
  private Artist artist;
  private String label;
  private Date releaseDate;
  private List<Track> tracks;

  /*
   .... standard getters/setters/equals/hashCode/toString
  */
}

Here is a basic Track:

import java.io.Serializable;
import javax.persistence.Entity;

@Entity
public class Track implements Serializable
{
  private Integer id;
  private String title;
  private int lengthInSeconds;
  private Record record;
  /*
   .... standard getters/setters/equals/hashCode/toString
  */
}

Finally, here’s the Artist:

import java.io.Serializable;
import javax.persistence.Entity;

@Entity
public class Artist implements Serializable
{
  private Integer id;
  private String name;
  private String genre;
  /*
   .... standard getters/setters/equals/hashCode/toString
  */
}

The only thing that makes this at all interesting the the @Entity annotation at the class level. This simply indicates that we plan to persist this class with JPA. Here we could additionally provide the table name that this class will persist to; if you do not provide a table name, it assumes that the table name is the same name as the class.

When using the @Entity annotation, it is assumed that you will persist all JavaBean properties to the database. For getter/setters of Strings, primitives, and various number-related objects, we do not have to do anything additional if we want to map to columns of the same name as the property. In fact, we would have to tell it explicitly if we do not want to persist these properties.

The next interesting thing that we have to do is to annotate these POJOs to tell them about the identifiers/primary keys. On each of our classes, simply add the following annotation on the Integer getId() methods:

  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  public Integer getId()
  {
    return id;
  }

Now on the Record class I am going to map the owning Artist class as a ManyToOne like this:

  @ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE })
  public Artist getArtist()
  {
    return artist;
  }

For the sake of simplicity in this simple example, I am not going to map the reverse association.

Next map the List of Tracks to the Record class as a OneToMany:

  @OneToMany(cascade=CascadeType.ALL,
             fetch=FetchType.EAGER)
  public List<Track>getTracks()
  {
    return tracks;
  }

Finally, I will map the reverse association of the Record-to-Tracks relationship:

  @ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE} )
  public Record getRecord()
  {
    return record;
  }

One last interesting annotation, let’s add a NamedQuery for the Record at the class level to allow us to search for records by title:

@Entity
@NamedQuery(name="record.titleLike",
            query="select r from Record r where r.title like ?")
public class Record implements Serializable
{
  //...
}

That’s the end of our JPA stuff. Now let’s create a DAO and wire it up with Spring.

Here’s our basic DAO interface:

public interface MusicDAO
{
  public Collection<Artist> getArtists();

  /**
   * Get a Artist Object given the id
   * @param id
   */
  public Artist getArtistById(Integer id);

  /**
   * Save an Artist Object
   */
  public Artist saveArtist(Artist artist);

  /**
   * Get a Record given the id
   * @param id
   */
  public Record getRecordById(Integer id);

  /**
   * Save a record
   * @param record
   */
  public Record saveRecord(Record record);

  /**
   * Search records given the title of the record
   * @param title
   */
  public List<Record> searchRecordsByTitle(String title);
}

I’ll implement this interface using Spring’s HibernateDaoSupport as in my previous Hibernate example:

/**
 * Implementation of MusicDAO implemented by extending Spring's HibernateDaoSupport
 * @author roblambert
 */
public class MusicDAOHibernateImpl extends HibernateDaoSupport implements MusicDAO
{
  public Collection<Artist> getArtists()
  {
    return getHibernateTemplate().loadAll(Artist.class);
  }

  public Artist getArtistById(Integer id)
  {
    Artist artist = (Artist) getHibernateTemplate().load(Artist.class, id);
    return artist;
  }

  public Artist saveArtist(Artist artist)
  {
    getHibernateTemplate().saveOrUpdate(artist);
    return artist;
  }

  public Record getRecordById(Integer id)
  {
    Record record = (Record) getHibernateTemplate().load(Record.class, id);
    return record;
  }

  public Record saveRecord(Record record)
  {
    getHibernateTemplate().saveOrUpdate(record);
    return record;
  } 

  public Track getTrackById(Integer id)
  {
    Track track = (Track) getHibernateTemplate().load(Track.class, id);
    return track;
  }

  public List<Record> searchRecordsByTitle(String title)
  {
    return getHibernateTemplate().findByNamedQuery("record.titleLike", "%"+title+"%");
  }
}

Now, different from the previous Hibernate example, we will wire this whole thing up with Spring’s AnnotationSessionFactoryBean. This is what gives us support for making the system aware the of mappings for persistence using the annotations.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
  <bean id="sessionFactory"
        class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    <property name="hibernateProperties">

      <props>
<!--YOUR HIBERNATE PROPERTIES HERE...-->
      </props>
    </property>
    <property name="annotatedClasses">
      <list>

        <value>com.zabada.springrecipes.hibernatejpa.entity.Track</value>
        <value>com.zabada.springrecipes.hibernatejpa.entity.Record</value>
        <value>com.zabada.springrecipes.hibernatejpa.entity.Artist</value>
      </list>

    </property>
  </bean>

  <!--sessionFactory will get autowired-->
  <bean id="hibernateInterceptor"
        class="org.springframework.orm.hibernate3.HibernateInterceptor"
        autowire="byName" />

  <!--sessionFactory will get autowired-->

  <bean id="musicDaoTarget"
        class="com.zabada.springrecipes.hibernatejpa.dao.MusicDAOHibernateImpl"
        autowire="byName" />

  <bean id="musicDAO" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="proxyInterfaces">
      <value>com.zabada.springrecipes.hibernatejpa.dao.MusicDAO</value>
    </property>

    <property name="interceptorNames">
      <list>
        <value>hibernateInterceptor</value>
        <value>musicDaoTarget</value>
      </list>

    </property>
  </bean>

</beans>

There is nothing very tricky here that this any different from my previous Hibernate example. The only major difference is that the “sessionFactory” is built with a AnnotationSessionFactoryBean bean.
Note the annotatedClass property of the AnnotationSessionFactoryBean bean. I believe that you can use package-level definitions instead defining every persisted class by name.


The attached zip below is a Maven 2 project that is a self-contained project to illustrate the example above.

The prerequisites are:

The sample project is wired up to create/drop an in-memory HSQL database to demonstrate the persistence. Check out the JUnit test MusicDAOHibernateImplTest.java to see this example in action.

To run the project, unzip it, cd to the extracted directory and run:

mvn install

If you want to import the project into Eclipse, first run:

mvn eclipse:eclipse

and then import it into Eclipse.

Download JPA Spring Example

Further Reading

  • Java Persistence with Hibernate - Highly recommended (although no Spring coverage; the Hibernate/JBoss guys authored this book and they hate the Spring guys :) )

Next: Accessing a Remote EJB Via Spring