Mapping Enum Types with Hibernate Example
In this tutorial we show how to persist Java Enum types using Hibernate. Hibernate supports the mapping of Java enums as basic value types in various ways.
- The
@Enumerated
annotation is the original JPA-compliant way to map enums. This way, enums are stored according to one of two strategies.- Using
EnumType.ORDINAL
: stores the enum according to the enum value’s ordinal position within the enum class. - Using
EnumType.STRING
: stores the enum according to the enum value’s name.
- Using
- The
@Convert
annotation in addition to theAttributeConverter
. This allows you to map enums with attributes, which imho is the best way to store enums.
Maven Dependencies
We use Apache Maven to manage the projects dependencies. Add the following dependencies to your projects pom.xml
file.
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.4</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.3.Final</version>
</dependency>
Creating the Java Enum
Here is a simple Java enum called Activity
which we need to store in the database.
package com.memorynotfound.hibernate;
public enum Status {
PENDING("P"),
ACTIVE("A"),
INACTIVE("I"),
DELETED("D");
private String code;
Status(String code) {
this.code = code;
}
public String getCode() {
return code;
}
public static Status fromCode(String code) {
for (Status status :Status.values()){
if (status.getCode().equals(code)){
return status;
}
}
throw new UnsupportedOperationException(
"The code " + code + " is not supported!");
}
}
Mapping Enum Types with Hibernate Using Annotations
As we mentioned earlier, there are a couple of ways to map enum types using Hibernate. The first enum called ordinal
is mapped using the @Enumerated(EnumType.ORDINAL)
and will be stored using the ordinal order of the enum.
The second enum called string
is mapped using the @Enumerated(EnumType.STRING)
, which means that the name of the enum will be stored in the database.
The last enum called converted
is mapped using the @Converter
annotation and uses a custom AttributeConverter
called StatusConverter
which we’ll see in a moment. This is the most flexible solution to store enums.
package com.memorynotfound.hibernate;
import javax.persistence.*;
import java.util.Date;
@Entity
public class Activity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Enumerated(EnumType.ORDINAL)
private Status ordinal;
@Enumerated(EnumType.STRING)
private Status string;
@Convert(converter = StatusConverter.class)
private Status converted;
public Activity() {
}
public Activity(Status ordinal, Status string, Status converted) {
this.ordinal = ordinal;
this.string = string;
this.converted = converted;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Status getOrdinal() {
return ordinal;
}
public void setOrdinal(Status ordinal) {
this.ordinal = ordinal;
}
public Status getString() {
return string;
}
public void setString(Status string) {
this.string = string;
}
public Status getConverted() {
return converted;
}
public void setConverted(Status converted) {
this.converted = converted;
}
@Override
public String toString() {
return "Activity{" +
"id=" + id +
", ordinal=" + ordinal +
", string=" + string +
", converted=" + converted +
'}';
}
}
Be careful with EnumType.ORDINAL
: this can introduce undesirable results when you introduce a new enum before existing enums. Because this is based upon the ordinal position of the enum inside the class.
Mapping Enums with AttributeConverter and @Convert
A class that implements the AttributeConverter
interface can be used to convert entity attribute state into database column representation and back again.
package com.memorynotfound.hibernate;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
@Converter
public class StatusConverter implements AttributeConverter<Status, String> {
public String convertToDatabaseColumn(Status value) {
if ( value == null ) {
return null;
}
return value.getCode();
}
public Status convertToEntityAttribute(String value) {
if ( value == null ) {
return null;
}
return Status.fromCode(value);
}
}
Mapping Enum Types with Hibernate Using XML
If you prefer Hibernate XML HBM Mapping files over Annotations, you can use the equivalent hibernate xml mapping. This file is located in the src/main/resources
folder and is named Activity.hbm.xml
.
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.memorynotfound.hibernate.Activity">
<id name="id" type="java.lang.Integer">
<generator class="identity" />
</id>
<property name="string">
<type name="org.hibernate.type.EnumType">
<param name="enumClass">com.memorynotfound.hibernate.Status</param>
<param name="useNamed">true</param>
</type>
</property>
<property name="ordinal">
<type name="org.hibernate.type.EnumType">
<param name="enumClass">com.memorynotfound.hibernate.Status</param>
<param name="useNamed">false</param>
</type>
</property>
</class>
</hibernate-mapping>
Configure Hibernate Connection Properties
We can configure the database properties using the hibernate hibernate.cfg.xml
file, located on the classpath in the src/main/resources
folder.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- database connection properties -->
<property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/datestore?serverTimezone=Europe/Brussels</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password"></property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- show mysql queries output in console -->
<property name="hibernate.show_sql">true</property>
<!-- manage automatic database creation -->
<property name="hibernate.hbm2ddl.auto">create-drop</property>
<!-- add annotated resources here-->
<mapping class="com.memorynotfound.hibernate.Activity"/>
</session-factory>
</hibernate-configuration>
HibernateUtil
This class is used to configure hibernate during startup and create a standalone SessionFactory
.
package com.memorynotfound.hibernate;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static final SessionFactory sessionFactory;
static {
try {
sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
}
public static Session getSession() throws HibernateException {
return sessionFactory.openSession();
}
public static void shutdown() {
sessionFactory.close();
}
}
Running and Testing Java Enum mappings
package com.memorynotfound.hibernate;
import org.hibernate.Session;
import org.hibernate.Transaction;
import java.util.Arrays;
import java.util.List;
public class App {
public static void main (String...args){
Session session = HibernateUtil.getSession();
Transaction tx = session.beginTransaction();
Activity date = new Activity(Status.ACTIVE, Status.ACTIVE, Status.ACTIVE);
session.save(date);
tx.commit();
List<Activity> activities = (List<Activity>)session.createQuery("from Activity").list();
System.out.println(Arrays.toString(activities.toArray()));
session.close();
HibernateUtil.shutdown();
}
}
...
Hibernate: insert into Activity (string, ordinal) values (?, ?)
Hibernate: select activity0_.id as id1_0_, activity0_.string as string2_0_, activity0_.ordinal as ordinal3_0_ from Activity activity0_
[Activity{id=1, ordinal=ACTIVE, string=ACTIVE, converted=ACTIVE}]
...
Hi, mapping Hibernate Using XML Status field? Thanks