Enterprise Java

JPA 2.1 Type Converter – The better way to persist enums

Persisting enums with JPA 2.0 is possible, but there is no nice way to do it. Using the @Enumerated annotation, you can use EnumType.ORDINAL or EnumType.STRING to map the enum value to its database representation. But both options have some drawbacks, that we will discuss in the first part of this article. In the second part, I will show you to avoid these drawbacks by using a JPA 2.1 Type Converter.

Persisting enums with JPA 2.0

EnumType.ORDINAL uses the return value of Enum.ordinal() to persist the enum. So the first value of the enum will be mapped to 0, the second to 1 and so on. While this looks compact and easy to use in the first place, it causes problems when changing the enum. Removing enum values or adding a new value somewhere in between will change the mapping of all following values, e.g.:

before:

Vehicle:
CAR     -> 0
TRAIN   -> 1
PLANE   -> 2

after:

Vehicle:
CAR     -> 0
BUS     -> 1
TRAIN   -> 2
PLANE   -> 3

Adding Bus at the second position would require a database update to fix the enum mapping.

EnumType.STRING looks like a better option. It uses the String representation of the enum to persist it in the database. So adding or removing values will not change the mapping. But this representation can be quite verbose and renaming an enum value will break the mapping.

before: 

Vehicle:
CAR     -> CAR
TRAIN   -> TRAIN
PLANE   -> PLANE

after:

Vehicle:
CAR     -> CAR
BUS     -> BUS
TRAIN   -> TRAIN
PLANE   -> PLANE

Using JPA 2.1 Type Converter

JPA 2.1 Type Converter provide a third and in my opinion the best option. A Type Converter allows us to implement methods to convert the value of an entity attribute to its database representation and back. I will not get into too much details on how to implement a Type Converter because I already did this in one of my former articles.

By implementing our own mapping, we can choose a compact database representation and make sure, that changing the enum in any way will not break the existing mapping. The following example shows how to implement a type converter for the Vehicle enum:

@Converter(autoApply = true)
public class VehicleConverter implements AttributeConverter<Vehicle, String> {

 @Override
 public String convertToDatabaseColumn(Vehicle vehicle) {
  switch (vehicle) {
  case BUS:
   return "B";
  case CAR:
   return "C";
  case PLANE:
   return "P";
  case TRAIN:
   return "T";
  default:
   throw new IllegalArgumentException("Unknown value: " + vehicle);
  }
 }

 @Override
 public Vehicle convertToEntityAttribute(String dbData) {
  switch (dbData) {
  case "B":
   return Vehicle.BUS;
  case "C":
   return Vehicle.CAR;
  case "P":
   return Vehicle.PLANE;
  case "T":
   return Vehicle.TRAIN;
  default:
   throw new IllegalArgumentException("Unknown value: " + dbData);
  }
 }

}

The VehicleConverter maps the enum value to a one character String. By declaring it with @Converter(autoApply = true), we tell the JPA provider to use this Type Mapper to map all Vehicle enums. So we do not need to specify the converter at each entity attribute of type Vehicle.

But there is one thing we need to take care of and if you have read my former article about JPA Type Converter you might have wondered already. Type Converter cannot be applied to attributes annotated with @Enumerated. So we have to make sure that there is no @Enumerated annotation at our entity attributes of type Vehicle.

Conclusion

We implemented a simple Type Converter that uses our own rules to convert the Vehicle enum to its database representation. So we can make sure that changing the values of the Vehicle enum will not break the existing/remaining mappings.

Thorben Janssen

Thorben Janssen is a senior developer with more than 10 years of experience in Java EE development and architecture. During these years he acted as developer, architect, project and/or technical lead to create high available, clustered mobile billing solutions and laboratory information management systems.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button