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.
    1. Using EnumType.ORDINAL: stores the enum according to the enum value’s ordinal position within the enum class.
    2. Using EnumType.STRING: stores the enum according to the enum value’s name.
  • The @Convert annotation in addition to the AttributeConverter. 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}]
...

References

Download

You may also like...