Java Persistence API (JPA) Plugin

With this plugin, VRaptor2 manages the EntityManager lifecycle. That means VRaptor2 will create, destroy and flush it for you.

The plugin also keeps your javax.persistence.EntityManager active until your view is rendered, solving problems listed in the hibernate open-session-in-view article.

When an exception is thrown, any transaction executing will be rolled back.

If you want, the plugin can also start a new transaction before your logic executes (transaction.begin()) and commit it after your logic finishes (transaction.commit()).

The simple steps are:

  1. Register the plugin in vraptor.xml
  2. Annotate your model with java persistence api annotations
  3. Choose a Java Persistence API implementation
  4. Configure the persistence engine through the META-INF/persistence.xml file
  5. Manage your persistent objects in your logics

vraptor.xml

Open your vraptor.xml file and register the plugin:

<vraptor>
        ...
        <plugin>org.vraptor.plugin.jpa.JavaPersistencePlugin</plugin>
        ....
</vraptor>

Mapping your POJOs with Java Persistence Annotations

More details can be found on the good hibernate annotations documentation. You can also use the xml mapping files defined in the JPA specification.

Here we will only map a simple persistent class:

@Entity
public class User {

        @Id
        @GeneratedValue
        private Long id;

        private String name;

        private String email;

        private String password;

        //getters and setters
}

This is the simplest example.

@Entity tells the JPA engine it is a persistent class. @Id marks the primary key and @GeneratedValue tells the persistence provider to generate the primary keys (usually delegating that task to the underlying database).

There are a lot more annotations, please refer to the JPA documentation in the Java EE 5 tutorial.

Choose a Persistence Provider

There are two major choices for the persitence provider (JPA implementation):

  1. Hibernate through three subprojects: hibernate-core, hibernate-annotations and hibernate-entitymanager
  2. Oracle Toplink Essentials

Both are opensource and widely adopted. There are alternatives such as BEA Kodo and Apache OpenJPA. VRaptor2 with this plugin will work with any JPA compliant implementation.

You must choose one persistence provider and put the required jar(s) in your WEB-INF/lib folder.

Configure the persistence engine: the persistence.xml file

The Java Persistence API specification requires a META-INF/persistence.xml file for configuration. You must have the persistence.xml file inside the META-INF in your classpath. The easiest way is to put the META-INF/ dir in your sources folder and create a persistence.xml file inside.

Details about the persistence.xml file can be found in the JPA documentation.

VRaptor2 persistence plugin only requires that your persistence unit name must be default.

Take a look at an example for hibernate and HSQL database:

<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_1_0.xsd"
             version="1.0">
    <persistence-unit name="default">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <properties>
            <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
            <property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"/>
            <property name="hibernate.connection.username" value="sa"/>
            <property name="hibernate.connection.password" value=""/>
            <property name="hibernate.connection.url" value="jdbc:hsqldb:."/>
            <property name="hibernate.max_fetch_depth" value="3"/>
        </properties>
    </persistence-unit>
</persistence>

And another simple example for Oracle Toplink Essentials and MySQL database:

<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 persistence_1_0.xsd" version="1.0">
        <persistence-unit name="default">
                <provider>oracle.toplink.essentials.PersistenceProvider</provider>
                <exclude-unlisted-classes>false</exclude-unlisted-classes>
                <properties>
                        <property name="toplink.ddl-generation" value="drop-and-create-tables" />
                        <property name="toplink.logging.level" value="FINE" />
                        <property name="toplink.jdbc.url" value="jdbc:mysql://localhost/myDB" />
                        <property name="toplink.jdbc.driver" value="com.mysql.jdbc.Driver" />
                        <property name="toplink.jdbc.user" value="root" />
                        <property name="toplink.jdbc.password" value="" />
                </properties>
        </persistence-unit>
</persistence>

Managing your persistent objects

Just tell VRaptor2 to inject an EntityManager in your component.

Through JPA @PersistenceContext annotation:

import org.vraptor.annotations.Component;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Component
public class UserLogic {

    @PersistenceContext
    private EntityManager entityManager;

    public void save(User user) {
        this.entityManager.getTransaction().begin();
        this.entityManager.persist(user);
        this.entityManager.getTransaction().commit();
    }

    public void update(User user) {
        this.entityManager.getTransaction().begin();
        this.entityManager.merge(user);
        this.entityManager.getTransaction().commit();
    }
    // ...
}

or through constructor injection:

import org.vraptor.annotations.Component;
import javax.persistence.EntityManager;

@Component
public class UserLogic {

    private EntityManager entityManager;

    public UserLogic(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    public void save(User user) {
        this.entityManager.getTransaction().begin();
        this.entityManager.persist(user);
        this.entityManager.getTransaction().commit();
    }

    public void update(User user) {
        this.entityManager.getTransaction().begin();
        this.entityManager.merge(user);
        this.entityManager.getTransaction().commit();
    }
    // ...
}

Simple, eh?

Off course they are only simple examples. JPA is much more powerful and you still should encapsulate you data access code inside your DAOs.

Why my persistence unit must be called "default"?

That is only a convention used by the plugin, following the VRaptor2 conventions over configuration principle.

You still can use other name for your persistence unit, and inject an EntityManager from that persistence unit through @PersistenceContext:

@Component
public class UserLogic {

    @PersistenceContext(unitName="otherName")
    private EntityManager entityManager;

    public void save(User user) {
        this.entityManager.getTransaction().begin();
        this.entityManager.persist(user);
        this.entityManager.getTransaction().commit();
    }
    // ...
}

Can VRaptor2 handle my transactions?

Off course! You must only tell VRaptor2 that your logic method requires a transaction: @Transaction(required=true). The default behavior is "no transaction is required".

Then it will start a new transaction (transaction.begin()) before your logic executes and commit it (transaction.commit()) for you after your logic finishes.

That is the most common case for web applications. If it doesn't fit your case, then just don't tell VRaptor2 to manage your transaction and manage it the way you want, with entityManager.getTransaction().

If your logic throws an exception, any transaction executing (started by VRaptor2 or not) will be rolled back.

Example:

import org.vraptor.annotations.Component;
import org.vraptor.plugin.jpa.Transaction;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Component
public class UserLogic {

    @PersistenceContext
    private EntityManager entityManager;

    @Transaction(required=true)
    public void save(User user) {
        this.entityManager.persist(user);
    }
}