JPA and Hibernate enum mapping with annotations and the hbm.xml file
Just how hard is it to perform a JPA or Hibernate enum mapping with either annotations or a hbm.xml file? It’s actually not that hard at all. In fact, you don’t necessarily have to perform any mappings because the Hibernate defaults will take care of most of the low-level details for you.
JPA and Hibernate enum mapping
The Java enum, introduced in Java 5, will map to the underlying database without any intervention. The JPA framework, be it Hibernate or Toplink or DataNucleus, will recognize the Java enum and subsequently read or write the enums state to and fro. So it doesn’t require any additional annotations or coding in a hbm.xml file.
Whenever I need to prove out a concept, I always like to code up a little rock-paper-scissors program. In this use case, we can represent a competitor’s chosen gesture in the game as a Java enum:
package com.mcnz.rps; public enum Gesture { ROCK, PAPER, SCISSORS; }
Working with persistent entities
So long as any persistent object in the problem domain is decorated with the requisite @Entity and @Id attributes, the Java enum database mapping will proceed without error. The following is a JPA annotated entity that uses the Java enum named Gesture:
/* JPA & Hibernate enum mapping example */ package com.mcnz.rps; import javax.persistence.*; @Entity public class GameSummary { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Long id; private Gesture clientGesture; private Gesture serverGesture; private String result; private java.util.Date date = new java.util.Date(); public GameSummary(){} public GameSummary(Gesture clientGesture, Gesture serverGesture) { super(); this.clientGesture = clientGesture; this.serverGesture = serverGesture; } } /* End of Hibernate and JPA enum mapping example */
JPA and Java enum persistence
Now that we’ve created the Java enum and coded the JPA or Hibernate entity, all we need to do is give the JPA EntityManager or the Hibernate Session some attention and database persistence should be a lead-pipe cinch.
/* Entity that has a JPA/Hiberante mapped enum */ GameSummary gs = new GameSummary(); gs.clientGesture = Gesture.PAPER; gs.serverGesture = Gesture.ROCK; gs.result = "win"; /* Persisting the JPA/Hiberate mapped enum */ EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpa-enum-mapping"); EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); em.persist(gs); em.getTransaction().commit();
Java enums and the EnumType annotation
There is, however, a last-minute surprise with this Hibernate enum mapping approach. The ordinal number of the Java enum is written to the database, as opposed to an actual String. So the ROCK gesture is persisted as 0 and the PAPER gesture is persisted as 1.
To get the JPA or Hibernate enum mapping process to write text to the database instead of an ordinal number, the trick is to use the @Enumerated annotation in conjunction with @EnumType.
@Enumerated(EnumType.STRING) private Gesture clientGesture; @Enumerated(EnumType.STRING) private Gesture serverGesture;
Mapping with @Enumerated and @EnumType annotations
With the EnumType set to STRING as opposed to ORDINAL, the JPA and Hibernate enum mapping represents the Java enum with specific text instead of the enum’s ordinal value.
Of course, all of these mappings have used JPA. The concepts all map directly to Hibernate, although the syntax is slightly different, especially if you use a hbm.xml file for enum mapping for rows and columns. The XML would look as follows:
<property name="gesture" column="GESTURE"> <type name="org.hibernate.type.EnumType"> <param name="enumClass">com.mcnz.rps.Gesture</param> <param name="useNamed">true</param> </type> </property>
And without the useName parameter — or if the useName parameter is set to false — an ordinal value representing the enum is used, otherwise the String representation of the enum is persisted to the database.
And that’s it. Those are the ins and outs of using Hibernate and JPA enum mapping facilities.