Automatic JPA 2 Metamodel Generation Using Hibernate 5 and Gradle

The JPA 2 Metamodel provides a way to create JPA Criteria Queries in a type-safe manner. For Maven, there’s an integration provided directly by Hibernate. In this post, we’ll have a look at automatically generating the necessary JPA Metamodel classes with the Gradle build automation tool. Moreover, we’ll see how to use them in Spring Data JPA Specifications.


Preliminary

Suppose we have modeled a simple domain entity Person:

@Entity
public class Person {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long id;
    private String firstName;
    private String lastName;

    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}

For that entity, we want to generate a metamodel class like the following:

@Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
@StaticMetamodel(Person.class)
public abstract class Person_ {

	public static volatile SingularAttribute<Person, String> firstName;
	public static volatile SingularAttribute<Person, String> lastName;
	public static volatile SingularAttribute<Person, Long> id;

}

Setting up the Gradle build file

To automate the generation process with Gradle, we use the jpamodelgen-plugin. That plugin supports JPA Metamodel generation with Hibernate as the persistence provider out of the box.

With a little gradle scripting, the build.gradle file looks as follows:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:1.3.2.RELEASE")
    }
}

plugins {
  id "at.comm_unity.gradle.plugins.jpamodelgen" version "1.1.1"
}

apply plugin: 'spring-boot'
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'at.comm_unity.gradle.plugins.jpamodelgen'

repositories {
    jcenter()
    maven { url "https://repository.jboss.org/nexus/content/repositories/releases" }
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

dependencies {
    compile("org.springframework.boot:spring-boot-starter-data-jpa")
    compile("com.h2database:h2")
    testCompile("junit:junit")
}

sourceSets {
   generated {
        java.srcDir "${buildDir}/generated/src/java/"
    }
}

ext['hibernate.version'] = '5.0.7.Final'

jpaModelgen {
  library = "org.hibernate:hibernate-jpamodelgen:5.0.7.Final"
  jpaModelgenSourcesDir = "src/generated/java"
}

compileJava.options.compilerArgs += ["-proc:none"]

The plugin already provides an integration in the Gradle build lifecycle. The generation happens before the compileJava task. Moreover, the generated files are deleted when executing the clean task.

Please note, that we’ve switched to Hibernate version 5.0.7.Final. Moreover, we’ve added a separated sourceSet for the generated sources, so that they’re available on the classpath.

Usage with Spring Data

After all that setup, it is easy to use the Metamodel classes with Spring Data Specifications:

Specification<Person> byLastName(String lastName) {
    return (Root<Person> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {

        return cb.equal(root.get(Person_.lastName), lastName);
    };
}

Conclusion

As we’ve seen, Metamodel generation can be easily integrated into the Gradle build process. The plugin mechanism and scripting features of Gradle come in pretty handy here. If you are interested in writing more fluid queries than possible with the Criteria API, you should definitely have a look at the QueryDSL project.

References