Pure Danger Tech


navigation
home

Switching from Hibernate mapping files to JPA

15 Jul 2008

I’m just starting to build out an app that uses Hibernate. I started with Hibernate mapping files but switched over to using JPA annotations. I wanted to record the changes I needed to make and also a non-obvious exception (to my newbie eyes) and the solution.

When using Hibernate with mapping files you’ll have files like:

org/terracotta/reference/exam/domain/User.java
org/terracotta/reference/exam/domain/User.hbm.xml
org/terracotta/reference/exam/domain/HibernateUtil.java
hibernate.cfg.xml
log4j.properties

To switch to annotations, you’ll need to:

  1. Add hibernate-annotations and JPA jars
  2. Annotate your classes
  3. Modify hibernate.cfg.xml to use classes instead of mapping files
  4. Modify your HibernateUtil class to use a different configuration (this is the step that tripped me up)

To add the right jars, I’m using Maven and added the following additional dependencies:

<dependency>
  <groupId>javax.persistence</groupId>
  <artifactId>persistence-api</artifactId>
  <version>1.0</version>
</dependency>
<dependency>
  <groupId>org.hibernate</groupId>
  <artifactId>hibernate-annotations</artifactId>
  <version>3.3.1.GA</version>
</dependency>

There are many fine resources available on JPA annotations so I’m not going to discuss this in detail. You’ll have something that looks like this: [source:java]

@Entity

@Table(name = “USERS”)

public class User {</p>

@Id @GeneratedValue

@Column(name = “USER_ID”)

private Long id;

@Column(name = “FIRST_NAME”)

private String firstName;

@Column(name = “LAST_NAME”)

private String lastName;

@Column(name = “EMAIL”)

private String email;

// etc

}

[/source]

To update your hibernate.cfg.xml file, you’ll want to change lines like this:

<mapping resource="org/terracotta/reference/exam/domain/User.hbm.xml"/>

to something like this:

<mapping class="org.terracotta.reference.exam.domain.User">

If you did all that and stopped there, you might see an exception like this:

Exception in thread "main" java.lang.ExceptionInInitializerError
	at org.terracotta.reference.exam.domain.HibernateUtil.<clinit>(HibernateUtil.java:15)
	at org.terracotta.reference.exam.domain.Main.main(Main.java:12)
Caused by: org.hibernate.MappingException: An AnnotationConfiguration instance is required to use <mapping class="org.terracotta.reference.exam.domain.User"/>
	at org.hibernate.cfg.Configuration.parseMappingElement(Configuration.java:1600)
	at org.hibernate.cfg.Configuration.parseSessionFactory(Configuration.java:1555)
	at org.hibernate.cfg.Configuration.doConfigure(Configuration.java:1534)
	at org.hibernate.cfg.Configuration.doConfigure(Configuration.java:1508)
	at org.hibernate.cfg.Configuration.configure(Configuration.java:1428)
	at org.hibernate.cfg.Configuration.configure(Configuration.java:1414)
	at org.terracotta.reference.exam.domain.HibernateUtil.<clinit>(HibernateUtil.java:13)

And, like me, you would be puzzled. It turns out that when using annotations you need to use AnnotationConfiguration, which is a subclass of Configuration, specific to annotations. So, your HibernateUtil might look like this instead: [source:java]

package org.terracotta.reference.exam.domain;

import org.hibernate.SessionFactory;

import org.hibernate.cfg.AnnotationConfiguration;

public class HibernateUtil {

private static SessionFactory sessionFactory;

static {

try {

sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();

} catch(Throwable t) {

throw new ExceptionInInitializerError(t);

}

}

public static SessionFactory getSessionFactory() {

return sessionFactory;

}

public static void shutdown() {

getSessionFactory().close();

}

}

[/source]

Hope that helps someone down the line…