3 ways to serialize Java Enums
This article shows you best practice for serializing Java enums to database (via Hibernate, JPA) or file. It discusses three ways to serialize enums with code examples, the pros and cons of each way and also recommends the best way. You should know this if you are serializing an Object with an enum field to a file or mapping a POJO to a database table using technologies like Hibernate or JPA.
What exactly is a Java enum constant? A Java enum is a sub-class of java.lang.Enum. An enum constant is simply an object instance of the enum class. The enum constructor must be private. Enum constants are created by the JVM via an invocation of the private constructor. Customizing the constructor signature is the most common way of adding more data to the enum class. You can add methods to the enum class just like any other class.
What does serialization and deserialization of enum mean? Serialization involves converting the enum to a value (usually primitive or a String) which can be easily stored on the disk or a database. Deserialization involves reading a stored value and converting it back to an enum. It is important to understand the different ways in which enum serialization and deserialization works. Sometimes ORM implementations (like Hibernate) may automatically do the enum serialization for you, however there are drawbacks to some of these approaches that you should know.
Let’s say we want to serialize the following enum
public enum Color {
RED, GREEN, BLUE;
}
Following are 3 different approaches. The last approach is the most reliable way of serializing an enum class, however you should know approaches 1 and 2 so you can understand their drawbacks.
Approach 1: using the ordinal() value
Approach 2: using the name() value
Approach 3: Using a user defined business value – Best practice!
Approach 1: using the ordinal() value
Ordinal of an enum constant is the value is its position in its enum declaration. This is true for all enums. In the above example:
RED.ordinal() == 0 GREEN.ordinal() == 1 BLUE.ordinal() == 2
You can serialize the enum by converting the enum to its ordinal() value.
Color color = Color.GREEN; int ordinal = color.ordinal(); // ordinal == 1 // save ordinal
At a later point, you can deserialize the saved int using the values() method on the enum which returns all the enum constants in the order in this they were declared.
// retrieve from saved value Color savedColor = Color.values()[savedOrdinal];
This approach is simple and works. Some ORM implementations may automatically use this approach if you map your enum to and Integer column. However, the biggest drawback of this approach is that if new constants are introduced out of order then the serialized values will not be properly reconstructed.
Here’s the error scenario:
- Serialize an enum value Color.GREEN. Saved value gets stored as 1
- Developer adds a new color ORANGE between RED and GREEN
- The previously serialized value of 1 is now mapped to ORANGE.
Approach 2: using the name() value
The name() of any enum is the literal that is used to represent the enum constant in the Java program.
RED.name().equals("RED")
GREEN.name().equals("GREEN")
BLUE.name().equals("BLUE")
Serialize as follows:
Color color = Color.GREEN; String savedValue = color.name(); // save value
Deserialize as follows:
Color savedColor = Color.valueOf(savedValue);
valueOf() is a built-in method which returns the enum constant with the specified specified name
This method works as well. Some ORM implementations may automatically use this approach if you map your enum to and String (char, varchar) column.The serialized form is String (as opposed to int in the previous example). The main drawback of this approach is that the serialized value, which can then be stored on disk or in database and can be persisted for a long term, is now dependent on a Java constant name. A developer may accidentally rename the constant name without realizing that it will make the previously serialized values unreadable.
Here’s the error scenario:
- Serialize an enum value Color.GREEN. Saved value gets stored as “GREEN”
- Developer renamed enum constant from Color.GREEN to Color.Green.
- The previously serialized value of “GREEN” can no longer be mapped to an existing color.
Approach 3: Using a user defined business value – Recommended approach!
This approach involves assigning a an explicit user defined value to each enum constant and defining a toValue() and fromValue() methods on the enum to do the serialization and deserialization.
public enum Color {
RED("RED"), GREEN("GREEN"), BLUE("BLUE"), UNKNOWN("UNKNOWN");
private final String value;
Color(String value) {
this.value = value;
}
public static Color fromValue(String value) {
if (value != null) {
for (Color color : values()) {
if (color.value.equals(value)) {
return color;
}
}
}
// you may return a default value
return getDefault();
// or throw an exception
// throw new IllegalArgumentException("Invalid color: " + value);
}
public String toValue() {
return value;
}
public static Color getDefault() {
return UNKNOWN;
}
}
This approach is better than approach 1 and approach 2 above. It neither depends on the order in which the enum constants are declared nor on the constant names.
To serialize:
Color color = Color.GREEN; String savedValue = color.value(); // save value
To deserialize:
Color savedColor = Color.fromValue(savedValue);
Note: You can choose an Integer instead of String as a value, but remember this value must not change or you will be unable to retrieve you persisted values.
Mapping enum to database column using JPA/Hibernate
You can use any of the 3 approaches discussed above.
- Map the enum to an integer column. The persistence implementation should automatically convert enum to ordinal() and back for you.
- Map the enum to a String column. The persistence implementation should automatically convert the enum value to String value via the name() function.
- Map the enum using a business value. You should mark the enum field as @Transient, and create another String field which you can map to a String column in your database table. Here’s an example code snippet.
@Entity
public class Product {
@Column
private String colorValue;
@Transient
public Color getColor() {
return Color.fromValue(colorValue);
}
public void setColor(Color color) {
this.colorValue = color.toValue();
}
}
Conclusion
We saw 3 different ways to serialized enums in this article. Approach 1 and 2 above use ordinal() and name() respectively, and require no additional work, but are inherently unsafe to use. The safest way is approach 3 which uses a custom user defined value as shown in the example above. When persisting enums with Hibernate/JPA first convert them to a user defined value.
Related posts:

I have used a variant of option 3 (a derivative of option 2) for hibernate, store the enum class (.getClass()) and the name (.name()) as a string in the database seperated by something you know will never occur (space, colon, etc.) This way you store a fully qualified field name for the enum value that you have stored.
That way you can write some simple (and generic) reflection code to convert to and from the enum value, returning a default value (or null) if the enum has changed somehow.
good 1
Your approach 3 is pretty error prone. You should use a Hibernate UserType to do the mapping automatically.
Using name() has the drawback that I mentioned. If the developer renames the enum constant, you won’t be able to retrieve the old value.
Could you describe or provide a use case how approach 3 is error prone.
I concur with Joerg that this is the perfect case for the Hibernate UserType. As soon as someone provides a mutator for the colorValue field, hell will break loose.
And that can happen if you want hibernate to use accessors for the attributes instead of modifying directly the fields.
Rafael, can you elaborate why providing a setter (or mutator) method for colorValue field will break the implementation?
Your problem with approach 2 above is that a developer could change the name of the enum, from “GREEN” to “Green” in your example. But surely the same could happen with your preferred “business-value” approach ie. the developer could just as easily change the business-value as he could the enum name?
While approach 3 may give a level of indirection, I think in the long run having a divergence between the enum name and business-value could just end up being more problematic.
Jeremy, you have a fair point. I agree that the difference is just one level of indirection, but a very useful one. It moves the persisted value from the “developer space” to “business space”. I think the change in “business-value” will come from business stakeholders and not the developer and that is what makes approach 3 the most robust, at the cost of simplicity. I use approach 3 most of the times, and approach 2 when I am working on a one person project and I know that I will not change the constant name.
I agree that if theoretically enum constant is dramatically changed, then the divergence between enum name and business-value could be confusing. I just think that it is an uncommon case, the more common case is minor tweaks in the name by the developer, adding/removing underscores, uppercase/lowercase/camelcase modifications.
We use something similar to example 3 with a Hibernate UserType. Now we have a requirement to create lookups for all our enum values in our database. Not sure if there’s a simple way to do that…