Cheat Sheet: New Features in JPA 2.1

JPA became more powerful and easier to use with the latest update. Are you wondering what these changes are and how to use them?

The 5 page cheat sheet New Features in JPA 2.1 provides you with the information you need. You get:

- a short explanation for each feature,
- code snippets showing how to use them and
- links to more detailed articles.

Signup now and get the New Features in JPA 2.1 cheat sheet and regular blog updates for free.

I respect your privacy and have ZERO TOLERANCE for spam!

JPA 2.1 Attribute 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 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 much 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 {
 CAR("C"), BUS("B"), TRAIN("T"), PLANE("P");

 private String shortName;

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

 public String getShortName() {
  return this.shortName;
 }

 public static Vehicle fromShortName(String shortName) {
  for (Vehicle v : Vehicle.values()) {
   if (v.getShortName().equals(shortName)) {
    return v;
   }
  }

  throw new IllegalArgumentException("No Vehicle with shortName ["
    + shortName + "] found.");
 }
}

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 {

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

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

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 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 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 {

 @Id
 @GeneratedValue(strategy = GenerationType.IDENTITY)
 private Integer id;

 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 named queries:
@NamedQueries(@NamedQuery(name = "Trip.findByVehicle", query = "SELECT trip FROM Trip trip WHERE vehicle=:vehicle"))
public List findTripsByVehicle(Vehicle vehicle) {
 Query query = this.em.createNamedQuery("Trip.findByVehicle");
 query.setParameter("vehicle", vehicle);
 return query.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!

If you enjoyed reading this article and like to learn more about other Java EE7 features, make sure to subscribe to my RSS feed or follow me on twitter or google+.

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.

5 comments:

  1. Maybe the best solution would be use a generic type converter in order to manage all enums. In your example for each enum we have to create a converter.

    ReplyDelete
    Replies
    1. 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

      Delete
  2. Even nicer would be to add a visitor to the enum and to use it inside the converter. That way the compiler would notify you in case the enum has changed.

    ReplyDelete
    Replies
    1. Hi Frisian

      You are right, using a visitor would be even better. I will use that for my real applications. Thanks!

      Regards,
      Thorben

      Delete
  3. I'd be happy if I could just change the JPA default from ORDINAL to STRING.

    ReplyDelete