The Best Way To Store Enums with JPA and Hibernate

Storing enums in a database can be somewhat tricky. JPA and Hibernate provide 2 standard ways of storing enums: as text or as a number. Each of these ways has its disadvantages. In this post I will describe these disadvantages and then I’m going to reveal a third way, which solves all of them.

First Standard Way: Storing as Numbers

This is exactly what it sounds like. When storing an enum value in a database column, the column data type is a number (most commonly integer) and it stores the ordinal value of the enum constant.

For instance, if we have this enum:

public enum UserStatus {
    ACTIVE,
    INACTIVE,
    DELETED;
}

…the database column would contain 0 for ACTIVE, 1 for INACTIVE, or 2 for DELETED. This approach has 2 main disadvantages:

  1. It is difficult to troubleshoot. If you are trying to find out what’s happening in your database and look at the data in the table, you only see numbers and you have to remember their meanings.
  2. Editing the enum can easily result in broken functionality. If you alter the order of the enum constants in any way, their ordinal values change also, which will lead to errors when reading the existing values from the database. To prevent this once your enum values are stored in a database, you cannot change the order of the constants. If you want to add a new constant, you can only add it to the last position. Also you cannot delete any existing constant (even if it’s not used anymore), because this would change the values of the following constants.

If you choose to store enums as numbers, this is how to declare the field mapping:

@Enumerated(EnumType.ORDINAL)
private UserStatus status;

Second Standard Way: Storing as Strings

In this case, the database column contains the names of the enum constants. In our example the values are “ACTIVE”, “INACTIVE” and “DELETED”. The mapping is declared like this:

@Enumerated(EnumType.STRING)
private UserStatus status;

This approach (mostly) removes the disadvantages of the first one. You can freely change the order of the enum values, add new values to any place, and even remove old unused values (provided they are no longer in the database). However, once you store the values in the database, you cannot change their names. This limits your refactoring options. And if someone changes the names without realizing this fact, they will introduce errors into the code. Also the database columns have larger size, which can be a concern in large tables.

Alternative Way: Short String Identifiers

A very convenient way is to assign every enum value a short string identifier or a “shortcut”. This identifier would them be stored in the database column. In our example we could assign the following IDs to the values: ACTIVE – “ACT”, INACTIVE – “INA”, DELETED – “DEL”.

This approach removes all the disadvantages mentioned above. The IDs are easy to remember when troubleshooting the database. You can also modify the enum in any way (change order of values, add new values anywhere, delete unused values, rename values) as long as you don’t change the IDs. Also the column size remains fairly small. While the length of the IDs is optional, most enums will do with 3 characters. If you have enums with a lot of values, you can use 4 or more characters.

And it goes without saying that each value in an enum has to have a unique ID – the same ID cannot be used for 2 or more values.

How To Implement String Identifiers

I created a convenient open-source library which makes implementing enum string identifiers very easy. It’s called persistence-utils and you can find it on Github. Implementing the string identifiers with this library can be done by following these steps:

1. Add The Library To Your Classpath

If you’re using Maven, add the following dependency into your pom.xml:

<dependency>
    <groupId>com.jardoapps</groupId>
    <artifactId>persistence-utils</artifactId>
    <version>1.0.0</version>
</dependency>

2. Define The String IDs in Your Enum

Your enum has to implement interface PersistableEnum, which provides method getId().

public enum UserStatus implements PersistableEnum {

	ACTIVE("ACT"), INACTIVE("INA"), DELETED("DEL");

	private final String id;

	private UserStatus(String id) {
		this.id = id;
	}

	@Override
	public String getId() {
		return id;
	}

}

3. Add an Attribute Converter

Attribute converter is a class which takes care of converting your enum values to data stored in the database and the other way around. The persistence-utils library provides an implementation of this converter called PersistableEnumConverter. All you have to do is add a static class into your enum which extends PersistableEnumConverter.

public enum UserStatus implements PersistableEnum {

	ACTIVE("ACT"), INACTIVE("INA"), DELETED("DEL");

	private final String id;

	private UserStatus(String id) {
		this.id = id;
	}

	@Override
	public String getId() {
		return id;
	}

	@Converter(autoApply = true)
	public static class UserStatusConverter extends PersistableEnumConverter<UserStatus> {

	}

}

The annotation @Converter(autoApply = true) tells Hibernate to use this class for converting attributes whose type is our enum. The autoApply attribute says Hibernate should automatically use the converter on all entity attributes of type UserStatus without explicit definition. In order for this to work, make sure this enum can be read by Hibernates entity scan.

4. Use Lombok To Simplify The Enum Code (Optional)

You can use Lombok to generate the enum constructor and the getId() method. This makes the enum code cleaner and easier to read. If you’re not using Lombok, you can skip this step.

@Getter
@AllArgsConstructor
public enum UserStatus implements PersistableEnum {

	ACTIVE("ACT"), INACTIVE("INA"), DELETED("DEL");

	private final String id;

	@Converter(autoApply = true)
	public static class UserStatusConverter extends PersistableEnumConverter<UserStatus> {

	}

}

5. Use The Enum In Your Entity Attributes

After you’ve done the above steps, you can define attributes of UserStatus in your entity objects and everything should work. If you’re letting Hibernate generate your schema, don’t forget to specify the column length (same length as your IDs). In our example, the column length would be 3.

@Column(length = 3)
private UserStatus status;

Need a Mentor?

If you would like to improve your Java programming skills to apply for a developer position or get a raise at your current position, you can schedule a free mentoring session with me. In this session, we will go over your strengths an weaknesses and we will develop a custom learning strategy based on your needs.

==> Click here to reserve a free mentoring session.