JPA 2.1 Attribute Converter – The better way to persist enums

By Thorben Janssen

Best Practice, Mapping

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 their drawbacks. The ordinal of an Enum depends on the ordering of its values and can create problems, if we need to add new ones. The String representation of an Enum is often quite verbose and renaming a value will break the database mapping. These drawbacks can be avoided by using an Attribute Converter.

Implementing the Converter

An Attribute 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 a lot of details on how to implement an Attribute 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. Therefore we add the shortName, which will be used as the database representation, as an additional property to the Enum. We also need a method to get the shortName property and to get the enum for a given shortName.

public enum Vehicle {

	BUS("B"), CAR("C"), TRAIN("T"), PLANE("P");

	private String shortName;

	private Vehicle(String shortName) {
		this.shortName = shortName;
	}

	public String getShortName() {
		return shortName;
	}

	public static Vehicle fromShortName(String shortName) {
		switch (shortName) {
		case "B":
			return Vehicle.BUS;

		case "C":
			return Vehicle.CAR;

		case "T":
			return Vehicle.TRAIN;

		case "P":
			return Vehicle.PLANE;

		default:
			throw new IllegalArgumentException("ShortName [" + shortName
					+ "] not supported.");
		}
	}
}

Now we can implement the converter to use the shortName property to store the Enum in the database:

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

	@Override
	public String convertToDatabaseColumn(Vehicle vehicle) {
		return vehicle.getShortName();
	}

	@Override
	public Vehicle convertToEntityAttribute(String dbData) {
		return Vehicle.fromShortName(dbData);
	}

}

The VehicleConverter maps the enum value to the shortName to store it in the database. By declaring it with @Converter(autoApply = true), we tell the JPA provider to use it to map all Vehicle enums. So we do not need to specify the converter for 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 Attribute Converter you might have wondered already. Attribute 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.

@Entity
public class Trip {
	
	private Vehicle vehicle;

	...
}

Using the Converter

OK, implementing the Converter was easy. But how do we use it in the application?

This is one of the best parts of the Attribute Converter. We do not have to do anything. The persistence provider will use it for all read and write operations, e.g. in JPQL queries.

TypedQuery<Trip> q = em.createQuery("SELECT t FROM Trip t WHERE t.vehicle = :v", Trip.class);
q.setParameter("v", Vehicle.PLANE);
List<Trip> trips = q.getResultList();

Conclusion

We implemented a simple Attribute 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.

What do you think about using JPA Attribute Converter to persist enums? Please leave me a comment!

And if you like to read more about the features introduced with JPA 2.1, have a look at my JPA 2.1 overview: JPA 2.1 – 12 features every developer should know.


Tags

Best Practice, Mapping


About the author

Thorben is an independent consultant, international speaker, and trainer specialized in solving Java persistence problems with JPA and Hibernate.
He is also the author of Amazon’s bestselling book Hibernate Tips - More than 70 solutions to common Hibernate problems.

Books and Courses

Coaching and Consulting

Leave a Repl​​​​​y

Your email address will not be published. Required fields are marked

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

  1. ++

    Thanks for this post.
    I had been thinking about this too and implemented this a couple of days back in my toy example project. This blog post confirms that I am not going down the wrong path.

    I also tried creating a generic converter for all my enums like Gamal Mateo suggested, but could not figure out how to get it to work. So ended up having a converter for each enum in my app. 🙁

    I am curious about the comment that Frisian made about the visitor. Am not familiar with it, so plan to research it.

    Thanks for your post. informative.
    sgb.

    Reply

  2. Hi Gamal,

    thanks for your comment.
    I would love to create a generic type converter. But up to now, I have no idea how to implement the convertToEntityAttribute(String dbData) method in a generic way. The method has to create a specific enum and I have no idea how to get the required one. Any suggestions?

    Regards,
    Thorben

    PS: If you want to try something, you can find the source on github: https://github.com/somethoughtsonjava/JPA2.1-EnumConverter

    Reply

{"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}