/ HIBERNATE, JPA, PERSISTENCE

Framework agnostic JPA

With new JEE 5 standard has come the EJB3 specifications. From an historical point of view, EJBs come into 3 different flavors: (i) Entity for persistence, (ii) Session for business logic and (iii) Message-Driven for listeners. Entity EJB are the most time-consuming to develop in their 2.1 version. Apart from the inherent complexity of EJB (local and remote interfaces, homes), developing an EJB 2 is error-prone because of the mapping mechanism. All in all, EJB 2 development really needs a very specialized IDE and expert developers. That’s the main reason why EJB 2 didn’t achieve a significant market share, and had to compete with JDO, Hibernate and other third-party frameworks.

Sun eventually realized this and did come with a much simpler solution with EJB 3. Using Java 5 annotations, developing Entity EJB 3 is a breeze. The part of EJB 3 specifications that deal with Entity is called Java Persistence API (JPA). It is a specification in its own right, and in the next specifications, it will have its own. Developing JPA applications is a two-step process. First, you have to create you model classes. Such classes will be the foundation of your persistence layer: it would be a good idea to use this layer throughout your entire organization, since these classes should closely map your database model. A simple JPA enhanced class would look like this:

import static javax.persistence.GenerationType.IDENTITY;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Book implements Serializable {

    /** Unique class's serial version identifier. */
    private static final long serialVersionUID = 7292903017883188330L;

    /** Book's unique identifier. */
    @Id
    @GeneratedValue(strategy = IDENTITY)
    private long id;

    /** ISBN. */
    private String isbn;

    /** Book's title. */
    private String title;

    /** Publication's date. */
    private Date published;

    public long getId() {
        return id;
    }

    public String getIsbn() {
        return isbn;
    }

    public Date getPublished() {
        return published;
    }

    public String getTitle() {
        return title;
    }

    public void setId(long aId) {
        id = aId;
    }

    public void setIsbn(String aIsbn) {
        isbn = aIsbn;
    }

    public void setPublished(Date aPublished) {
        published = aPublished;
    }

    public void setTitle(String aTitle) {
        title = aTitle;
    }

You have noticed 3 annotations:

  • javax.persistence.Entity (line 9): just this annotation enables your model’s class to be used by JPA,
  • javax.persistence.Id (line 16): identifies the primary key column,
  • javax.persistence.GeneratedValue (line 17): how to generate PK while inserting.

Mapping your classes against the database is the most important operation of JPA. It is out of the scope of this article, suffice to say the least is you can do is use the 3 above annotations.

If you’re using Eclipse, and if you don’t want to learn all JPA annotations, I recommend using JPA facet. Just righ-click your project, select Properties and go to Project Facets. Then select Java Persistence. Apart from creating needed configuration files (see below) and providing a nice utility view for them, it allows two more views for each of you model classes:

  • JPA Structure which should map your database structure,
  • JPA Details where you can add and change JPA annotations.

JPA details in Eclipse

Once mapping is done, either through brute force or the neat little wizard provided just above, how can you CRUD theses entities? First, you can continue using your favorite JPA-compatible persistence framework. In my case, I use Hibernate, which happens to be JPA reference implementation. The following code is called once, preferably in an utility class:

AnnotationConfiguration configuration = new AnnotationConfiguration();
configuration.addAnnotatedClass(Book.class);
configuration.configure();
sessionFactory = configuration.buildSessionFactory();

Now you only have to get the session for every unit-of-work and use it in your <acronym title="Data Access Object">DAO</acronym>:

Session session = sessionFactory.getSession();
// Get every book in database
List books = session.createCriteria(Book.class).list();

Now we got model’s classes that are Hibernate independent but our DAOs are not. Since using JPA API instead of Hibernate API decouples our code from the underlying framework, and this at no significant performance cost, it becomes highly desirable to remove this dependency. You need to have :

  • a compile-time dependency to ejb3-persistence.jar,
  • a runtime dependency to hibernate-entitymanager.jar or its TopLink equivalent. Transitive dependencies are of course framework dependent.

JPA configuration is done through 2 files:

  • META-INF/orm.xml for mapping informations. In our case, it is already done with annotations.
  • META-INF/persistence.xml for meta information, e.g JNDI location of the datasource to use.

When done, the calling sequence is very similar to Hibernate’s:

// This done once per application
// Notice its similitude with Hibernate's SessionFactory
EntityManagerFactory emf = Persistence.createEntityManagerFactory("myManager");

// This done per unit of work
// Notice its similitude with Hibernate's Session
EntityManager em = emf.createEntityManager();

// Get every book in database
List books = em.createQuery("SELECT b FROM Book").getResultList();

Now, using the above code, passing from an Hibernate implementation to a TopLink implementation is transparent. Just remove Hibernate JARs and put TopLink JARs on the runtime classpath.

Nicolas Fränkel

Nicolas Fränkel

Nicolas Fränkel is a Developer Advocate with 15+ years experience consulting for many different customers, in a wide range of contexts (such as telecoms, banking, insurances, large retail and public sector). Usually working on Java/Java EE and Spring technologies, but with focused interests like Rich Internet Applications, Testing, CI/CD and DevOps. Currently working for Hazelcast. Also double as a teacher in universities and higher education schools, a trainer and triples as a book author.

Read More