JPQL Criteria MetaModel

In JPA2 there is a query API referred to as "criteria". This is really an API allowing the construction of queries expression by expression, and optionally making it type safe so that if you refactor a field name then it is changed in the queries. One mechanism for allowing refactoring of queries is to have something called a static metamodel of generated classes that mirror the applications persistable classes and have persistable fields marked as public and static so that they can be accessed when generating the queries.



Metamodel Definition

The JPA2 spec contains the following description of the static metamodel.

For every managed class in the persistence unit, a corresponding metamodel class is produced as follows:

  • For each managed class X in package p, a metamodel class X_ in package p is created.
  • The name of the metamodel class is derived from the name of the managed class by appending "_" to the name of the managed class.
  • The metamodel class X_ must be annotated with the javax.persistence.StaticMetamodel annotation
  • If class X extends another class S, where S is the most derived managed class (i.e., entity or mapped superclass) extended by X, then class X_ must extend class S_, where S_ is the meta-model class created for S.
  • For every persistent non-collection-valued attribute y declared by class X, where the type of y is Y, the metamodel class must contain a declaration as follows:
    public static volatile SingularAttribute<X, Y> y;
  • For every persistent collection-valued attribute z declared by class X, where the element type of z is Z, the metamodel class must contain a declaration as follows:
    • if the collection type of z is java.util.Collection, then
      public static volatile CollectionAttribute<X, Z> z;
    • if the collection type of z is java.util.Set, then
      public static volatile SetAttribute<X, Z> z;
    • if the collection type of z is java.util.List, then
      public static volatile ListAttribute<X, Z> z;
    • if the collection type of z is java.util.Map, then
      public static volatile MapAttribute<X, K, Z> z;
      where K is the type of the key of the map in class X

Let's take an example, for the following class

package org.datanucleus.samples.jpa2.metamodel;

import java.util.*;
import javax.persistence.*;

@Entity
public class Person
{
    @Id
    long id;

    String name;

    @OneToMany
    List<Address> addresses;
}

the static metamodel class will be

package org.datanucleus.samples.jpa2.metamodel;

import javax.persistence.metamodel.*;

@StaticMetamodel(Person.class)
public class Person_ 
{
    public static volatile SingularAttribute<Person, Long> id;
    public static volatile SingularAttribute<Person, String> name;
    public static volatile ListAttribute<Person, Address> addresses;
}


Generating the Static Metamodel

The DataNucleus JPA plugin contains an annotation processor that can be used when compiling your model classes to generate the static metamodel classes. To enable this you need to be using JDK1.6+ and to provide the compiler command line argument

-processor org.datanucleus.jpa.JPACriteriaProcessor

To enable this in Maven2 you would need the following in your POM

<plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
        <source>1.6</source>
        <target>1.6</target>
        <compilerArguments>
            <processor>org.datanucleus.jpa.JPACriteriaProcessor</processor>
        </compilerArguments>
    </configuration>
</plugin>

This will then create the static metamodel source files in the build area, and then compile them.