Learnitweb

Mapping enums in Hibernate

1. Introduction

In this tutorial, we’ll discuss mapping and persisting enums in Hibernate. An enum declaration looks like the following:

public enum FLAG {
      ON, OFF 
}

Each enum constant has an ordinal which represents the sequence in the enum declaration, where the initial constant is assigned an ordinal of 0. For example, ON has ordinal value 0, OFF as 1 and so on. You can persist enum’s value as well as ordinal value.

2. @Enumerated annotation

Using the JPA-compliant @Enumerated annotation is the most common approach of mapping enums. Enum values are persisted using two strategies:

  • ORDINAL
  • STRING

2.1 @Enumerated(EnumType.ORDINAL)

If you use @Enumerated(EnumType.ORDINAL) annotation on the enum field, JPA will use the Enum.ordinal() value when persisting a given entity in the database. EnumType.ORDINAL is the default strategy while persisting enum.
Following is the Entity, we’ll be using in this tutorial:

@Entity
public class Employee {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "id")
	private Long id;

	@Column(name = "name")
	private String name;

	@Enumerated(EnumType.ORDINAL)
	private Flag flag;
	
	// getter, setter omitted for brevity
}

Notice the use of @Enumerated(EnumType.ORDINAL) annotation. Following is the enum FLAG:

public enum Flag {
	OFF, ON
}

Using ORDINAL as the strategy, will save the following values:

  • NULL For null values
  • 0 For the OFF enum
  • 1 For the ON enum

Lets now save the Employee entity:

Employee employee = new Employee();
employee.setName("Dummy Name");
employee.setFlag(Flag.ON);
session.save(employee);

Hibernate will generate the following SQL statements:

insert into Employee (flag, name) values (?, ?)
binding parameter [1] as [INTEGER] - [1]
binding parameter [2] as [VARCHAR] - [Dummy Name]

Changing the order of the enum constants or inserting a new one will break the existing data model. So if there is a possibility of change in enum, EnumType.ORDINAL should not be preferred.

2.2 @Enumerated(EnumType.STRING)

If you use @Enumerated(EnumType.STRING) annotation on the enum field, JPA will use the Enum.name() value when persisting a given entity in the database. Lets now see the use of @Enumerated(EnumType.STRING).

@Entity
public class Employee {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "id")
	private Long id;

	@Column(name = "name")
	private String name;

	@Enumerated(EnumType.STRING)
	private Flag flag;
	
	// getter, setter omitted for brevity
}
public enum Flag {
	OFF, ON
}

Using ORDINAL as the strategy, will save the following values:

  • NULL For null values
  • OFF For the OFF enum
  • ON For the ON enum

Let us now persist the entity like the previous example,

Employee employee = new Employee();
employee.setName("Dummy Name");
employee.setFlag(Flag.ON);
session.save(employee);

Hibernate will generate the following SQL statements:

insert into Employee (flag, name) values (?, ?)
binding parameter [1] as [VARCHAR] - [ON]
binding parameter [2] as [VARCHAR] - [Dummy Name]

3. Using AttributeConverter

Suppose you want to save T (for True) for ON and F (for False) for OFF. You can achieve this by using AttributeConverter.

First, we’ll modify the enum FLAG.

public enum Flag {
	OFF('F'), ON('T');

	private final char code;

	Flag(char code) {
		this.code = code;
	}

	public static Flag fromCode(char code) {
		if (code == 'T' || code == 't') {
			return ON;
		}
		if (code == 'F' || code == 'f') {
			return OFF;
		}
		throw new UnsupportedOperationException("The code " + code + " is not supported!");
	}

	public char getCode() {
		return code;
	}
}

Next, we’ll modify the entity to use the converter with the enum field.

@Entity
public class Employee {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "id")
	private Long id;

	@Column(name = "name")
	private String name;

	@Convert(converter = FlagConverter.class)
	private Flag flag;
}

Next, we’ll create the converter.

@Converter
class FlagConverter implements AttributeConverter<Flag, Character> {

	public Character convertToDatabaseColumn(Flag value) {
		if (value == null) {
			return null;
		}

		return value.getCode();
	}

	public Flag convertToEntityAttribute(Character value) {
		if (value == null) {
			return null;
		}

		return Flag.fromCode(value);
	}
}

We’ll now save the entity like the previous example.

Employee employee = new Employee();
employee.setName("Dummy Name");
employee.setFlag(Flag.ON);
session.save(employee);

Hibernate will generate the following SQL queries:

insert into Employee (flag, name) values (?, ?)
AttributeConverterSqlTypeDescriptorAdapter - Converted value on binding : ON -> T
binding parameter [1] as [CHAR] - [T]
binding parameter [2] as [VARCHAR] - [Dummy Name]