Kick off your first JPA2 with Hibernate code

 Since Hibernate 3.5 CR2 was released recently, and the GA release is just around the corner, I decided to pick and test it as a JPA2 provider. I tried to Google for a "step-by-step" or even a sample project which uses JPA2 with Hibernate as its provider and haven't found any, so I decided to publish (the first?) one.

I tried to make this sample as simple as possible, yet demonstrate one of the innovation of JPA2: Type-safe Critaria API. Hibernate 3.5 uses a Java 6 annotation processor used to generate JPA 2 StaticMetamodel classes, intended mostly for use in JPA 2 criteria queries. The processor (JPAMetaModelEntityProcessor) processes all classes annotated with @Entity, as well as entities mapped in /META-INF/orm.xml and mapping files specified in persistence.xml.
On our example we'll have a "User" entity, and the processor will create a metamodel class "User_". The generated "User_" class enable us to run a type-safe criteria query. The generation of this class can be created either by the IDE or by a build tool (or both).

So without further words, lets start our first Maven JPA2+Hibernate project:
First we need to create the pom.xml which declares all the dependencies (including the Hibernate preprocessor jar to generate our "User_" class)

 

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mycompany.app</groupId>
    <artifactId>my-app</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>Maven Quick Start Archetype</name>
    <url>http://maven.apache.org</url>


    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.8.1</version>
            <scope>test</scope>
        </dependency>

        <!-- concrete Log4J Implementation for SLF4J API-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.5.11</version>
        </dependency>

        <!-- Hibernate generate Metamodel -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-jpamodelgen</artifactId>
            <version>1.0.0-CR-1</version>
            <scope>provided</scope>
        </dependency>

        <!-- Hibernate dependecies -->
        <dependency>
            <groupId>org.hibernate.java-persistence</groupId>
            <artifactId>jpa-api</artifactId>
            <version>2.0-cr-1</version>
        </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>3.5.0-CR-2</version>
        </dependency>

        <dependency>
            <groupId>hsqldb</groupId>
            <artifactId>hsqldb</artifactId>
            <version>1.8.0.7</version>
            <scope>runtime</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                    <compilerArgument>-proc:none</compilerArgument>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.bsc.maven</groupId>
                <artifactId>maven-processor-plugin</artifactId>
                <executions>
                    <execution>
                        <id>process</id>
                        <goals>
                            <goal>process</goal>
                        </goals>
                        <phase>generate-sources</phase>
                        <configuration>
                            <!-- source output directory -->
                            <outputDirectory>target/metamodel</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>build-helper-maven-plugin</artifactId>
                <version>1.5</version>
                <executions>
                    <execution>
                        <id>add-source</id>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>add-source</goal>
                        </goals>
                        <configuration>
                            <sources>
                                <source>target/metamodel</source>
                            </sources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>jboss</id>
            <url>http://repository.jboss.org/maven2</url>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>maven-annotation-plugin</id>
            <url>http://maven-annotation-plugin.googlecode.com/svn/trunk/mavenrepo</url>
        </pluginRepository>
    </pluginRepositories>
</project>

 

Now, lets create a simple entity "User":

 

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class User {

	User() {
	}

	public User(String name) {
		this.name = name;
	}

	@SuppressWarnings("unused")
	@GeneratedValue
	@Id
	private Integer id;

	private String name;

	public String getName() {
		return name;
	}

}

 

Next step is to create create a persistence.xml file under META-INF directory containing the DB properties (HSQL in memory DB in our case) , the entities , and a couple of Hibernate properties (auto-generate the schema and SQL dialect):

<?xml version="1.0" encoding="UTF-8"?>

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

    <persistence-unit name="sampleEM" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <class>com.tikal.sample.model.User</class>

        <properties>
            <property name="javax.persistence.jdbc.driver" value="org.hsqldb.jdbcDriver"/>
            <property name="javax.persistence.jdbc.url" value="jdbc:hsqldb:mem:aname"/>
            <property name="javax.persistence.jdbc.user" value="sa"/>
            <property name="javax.persistence.jdbc.password" value=""/>
            <!-- Hibernate required props -->
            <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
        </properties>

    </persistence-unit>

</persistence>

 

Thats all the source needed for the project!

Now you need to run "mvn install". This will generate java sources for the metamodel and compile it with all other Java sources in the project. In our case a new Java file, User_.java will be created at target/metamodel/com/tikal/sample/model folder:

@StaticMetamodel(User.class)
public abstract class User_ {

    public static volatile SingularAttribute<User, Integer> id;

    public static volatile SingularAttribute<User, String> name;

}

 

Lets unit test the code above, by creating a type-safe criteria query.

 

public class UserTest {

    private static EntityManagerFactory factory = Persistence.createEntityManagerFactory("sampleEM");

    @Test
    public void findUsers() {

        String name = "yanai";
        EntityManager em = factory.createEntityManager();
        EntityTransaction tx = null;
        try {
            tx = em.getTransaction();
            tx.begin();
            em.persist(new User(name));
            User loadedUser = loadUserByName(name, em);
            assert loadedUser.getName().equals(name);
            tx.commit();
        } catch (RuntimeException e) {
            if (tx != null && tx.isActive())
                tx.rollback();
            throw e;
        } finally {
            em.close();
        }
    }


    private User loadUserByName(String name, EntityManager em) {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<user> q = cb.createQuery(User.class);
        Root<user> user = q.from(User.class);
        q.select(user).where(cb.equal(user.get(User_.name), name));
        return em.createQuery(q).getSingleResult();
    }
}

 

If you look carefully at the "loadUserByName" method you can see that we use the "User_.name" as a type-safe predicate for our query:

q.select(user).where(cb.equal(user.get(User_.name), name));

 

Thats all. I hope this post helped you kick off and taste JPA2 with Hibernate.

Thank you for your interest!

We will contact you as soon as possible.

Send us a message

Oops, something went wrong
Please try again or contact us by email at info@tikalk.com