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:
- Add hibernate-annotations and JPA jars
- Annotate your classes
- Modify hibernate.cfg.xml to use classes instead of mapping files
- 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…