When you write a criteria query or create a dynamic entity graph, you need to reference the entity classes and their attributes. The quickest and easiest way is to provide the required names as Strings. But this has several drawbacks, e.g. you have to remember or look-up all the names of the entity attributes when you write the query. But it will also cause even greater issues at later phases of the project, if you have to refactor your entities and change the names of some attributes. In that case you have to use the search function of your IDE and try to find all Strings that reference the changed attributes. This is a tedious and error prone activity which will easily take up the most time of the refactoring.
Don’t want to read? You can watch it here!
Therefore I prefer to use the static metamodel to write criteria queries and dynamic entity graphs. This is a small feature defined by the JPA specification which provides a type-safe way to reference the entities and their properties.
As you can see in the code snippets below, I prepared a simple entity for this example. It represents an Author with an id, a first and a last name and a List of books she/he has written. I skip the Book entity here because we don’t need it for the following examples.
Static metamodel class
The class of the static metamodel looks similar to the entity. Based on the JPA specification, there is a corresponding metamodel class for every managed class in the persistence unit. You can find it in the same package and it has the same name as the corresponding managed class with an added ‘_’ at the end. So the metamodel class in this example is located in the package org.thoughts.on.java.model and has the name Author_.
As you see in the source code, the metamodel class Author_ provides an attribute for each attribute of the Author entity. Each metamodel attribute provides information about its type and the Entity to which it belongs.
Using metamodel classes
You can use the metamodel classes in the same way as you use the String reference to the entities and attributes. The APIs for criteria queries and dynamic entity graphs provide overloaded methods that accept Strings and implementations of the Attribute interface.
I use the metamodel class to create a criteria query to search for all Authors whose first name starts with “J”. As you can see, I use the same methods as I would do with the String references to the entity attributes.
As I described earlier, the metamodel classes can also be used to create dynamic entity graphs. You can see an example for this in the following code snippet.
Generating metamodel classes
OK, wait a second before you go ahead and start to create metamodel classes for your entities. There is no need for that. The JPA specification suggests to use an annotation processor to generate the metamodel classes and that is what the different implementations do. Unfortunately each and every implementation provides its own way for it.
I describe the required maven build configuration for Hibernate below. If you use a different JPA implementation (e.g. EclipseLink, OpenJPA) or build tool, please check the according documentation.
Adding the Hibernate Static Metamodel Generator to your build process is extremely simple. You only need to add it to your build classpath. The following code snippet shows the required dependency declaration for a maven build.
If you use maven, the generated metamodel classes are stored in the target/generated-classes folder. So you need to add this folder to the classpath definition in your IDE.
The static metamodel provides a type-safe and easy way to create criteria queries and dynamic entity graphs. This speeds up the initial implementation and makes future refactorings much easier than referencing the attributes via Strings.
The different persistence provider implementations provide annotation processors to generate the metamodel classes at build time. This makes sure, that changes on the entities are reflected on the metamodel and avoids bugs at runtime.