Type safe JPA queries

Quite often I find myself refactoring parts of my applications for different reasons and I am sure most developers do the same thing. Refactoring a java application is relatively easy since java is statically typed language and compiler will catch all type mismatches, moreover, modern IDEs like eclipse, intelij and netBeans provide all the necessary tools to accomplish this task as easily as possible. However, there is one part of the application that java compiler and IDE tools cannot do much. This part is the JPA queries which are String literals and there is no way for the compiler to catch any changes from the model. It seems that things will change with JPA 2.

JPA 2 introduces the Metamodel API (proposed by Gavin King) which is useful regardless of type safe queries. The metamodel exposes a set of interfaces which can be used to write  type safe queries with the new API. Other advantages of metamodel API besides the type safe queries are that it protects from SQL injection, auto-complete support through IDE, refactoring support.

Here is an example of how cool feature this is. Consider the following entities:


package org.chemistry.domain;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Substance {
	@Id
	private Long id;

	private String name;
	private String symbol;
	private double atomicWeight;
	private double grams;

	// getters and setters
	// ...
}

package org.chemistry.domain; import java.util.Set; import javax.persistence.Basic; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.OneToMany; @Entity public class Mixture { @Id private Long id; @Basic private String name; @OneToMany private Set<Substance> substances; // getters & setters // ... }

The metamodel classes for the entities will look like the following:


package org.chemistry.domain;

import javax.persistence.metamodel.*;

@TypesafeMetamodel
public class Substance_ {
	public static volatile Attribute<Substance, Long> id;
	public static volatile Attribute<Substance, String> name;
	public static volatile Attribute<Substance, String> symbol;
	public static volatile Attribute<Substance, Double> atomicWeight;
	public static volatile Attribute<Substance, Double> grams;
}

package org.chemistry.domain; import javax.persistence.metamodel.*; @TypesafeMetamodel public class Mixture_ { public static volatile Attribute<Mixture, Long> id; public static volatile Attribute<Mixture, String> name; public static volatile Set<Mixture, Substance> substances; }

Nothing impressive until now… the impressive part is how we can write the queries in a type safe way using the new criteria API. We can use the CriteriaQuery and the QueryBuilder to create the queries in the following way.


// get the entity manager
EntityManager em = ... ;

// JPQL
String query = "SELECT m.name FROM Mixture m JOIN m.substances s WHERE s.name = :name"
Query q = em.createQuery(query);
q.setParameter("name", "Beryllium");

// new query API
QueryBuilder qb = em.getQueryBuilder();
CriteriaQuery q = qb.create();
Root mixture = q.from(Mixture.class);
Join<Mixture, Substance> sub = mixture.join(Mixture_.substances);
q.where(qb.equals(sub.get(Substances_.name), "Beryllium")).select(mixture.get(Mixture_.name));

Now any refactoring in the Mixture or the Substance classes will immediately reflect the changes to the query. The metamodel classes are (or will be) auto generated by the time the entity class is compiled. So hopefully no more runtime exceptions because of domain model refactoring :)

This is JSR 317, here you can find all the necessary details about this cool API.