|

JPA 2.2 Introduces @Repeatable Annotations


Take your skills to the next level!

The Persistence Hub is the place to be for every Java developer. It gives you access to all my premium video courses, monthly Java Persistence News, monthly coding problems, and regular expert sessions.


JPA 2.2 was just a small maintenance release, but it nevertheless brought some interesting changes. You probably already know about some of the new features, like the retrieval of a query result as a Stream or the support for classes of the Date and Time API.

These are the most popular changes but not the only ones. JPA 2.2 also introduced a few smaller features that make it easier to use. One of them is that some of JPA’s annotations are now repeatable.

Before JPA 2.2

Up to Java 8, annotations had a major usability flaw. You were not allowed to annotate a class, method or attribute with multiple instances of the same annotation. That’s why JPA 2.1 used annotations, like @NamedQueries, that act as a container for an array of annotations. In this case, the @NamedQuery annotation.

@Entity
@NamedQueries({
	@NamedQuery(name = “Book.findByTitle”, query = “SELECT b FROM Book b WHERE b.title = :title”),
	@NamedQuery(name = “Book.findByPublishingDate”, query = “SELECT b FROM Book b WHERE b.publishingDate = :publishingDate”)
})
public class Book {
	...
}

A container annotation doesn’t provide any value on its own. It just wraps an array of other annotations. And since Java 8 and the introduction of repeatable annotations, you often don’t need to use container annotations anymore.

The Concept Of Repeatable Annotations

Before we dive into the details of repeatable JPA annotations, let’s quickly talk about the general concept of repeatable annotations.

The implementation of a repeatable annotation is pretty simple as you can see in the following code snippet. It shows JPA’s @NamedQuery annotation which became repeatable in version 2.2.

@Repeatable(NamedQueries.class)
@Target({TYPE}) 
@Retention(RUNTIME)
public @interface NamedQuery { ... }

The only change compared to JPA 2.1 is the additional @Repeatable(NamedQueries.class) annotation. It declares the container annotation which the Java compiler will use to generate the code that stores the repeating annotations. In this case, it’s the well known @NamedQueries annotation. I’m sure that you’re already using it in your projects to store an array of @NamedQuery annotations.

@Target({TYPE})  
@Retention(RUNTIME) 
public @interface NamedQueries { 

    /** (Required) An array of <code>NamedQuery</code> annotations. */
     NamedQuery [] value (); 
}

As you can see, your JPA implementation still needs to provide the container annotations. But you no longer need to use them in your code. You can annotate your entity class with multiple, repeatable annotations and the Java compiler will generate the code that stores them in a container annotation.

Repeatable Annotations In JPA 2.2

JPA 2.2 introduced 2 new container annotations and 16 annotations became repeatable. The new container annotations are TableGenerators and SequenceGenerators which store multiple TableGenerator and SequenceGenerator annotations. And you can find all repeatable annotations in the following table.

AnnotationDescription
AssociationOverrideOverride the mapping for an entity relationship.
AttributeOverrideOverride the mapping of a Basic property.
ConvertActivates or deactivates an AttributeConverter for a Basic property.
JoinColumnDefines a join column for an association or element collection.
MapKeyJoinColumnDefines the mapping to an entity that’s used as the map key.
NamedEntityGraphSpecifies a graph of entities that are fetched with a query.
NamedNativeQueryDefines a named native SQL query.
NamedQueryDefines a named JPQL query.
NamedStoredProcedureQueryDefines a named stored procedure query.
PersistenceContextReferences a container-managed EntityManager.
PersistenceUnitReferences a EntityManagerFactory and its associated persistence unit.
PrimaryKeyJoinColumnReferences a primary key column that’s used as a foreign key to join to another table.
SecondaryTableDefines a secondary database table that’s mapped by the entity.
SqlResultSetMappingDefines the mapping of the result of native SQL query.
SequenceGeneratorDefines the sequence based primary key generator that’s referenced by a GeneratedValue annotation.
TableGeneratorDefines the table based primary key generator that’s referenced by a GeneratedValue annotation.

With the change to repeatable annotations, you no longer need to wrap any of these annotations in a container annotation. As you can see in the following code snippet, the code becomes easier to write and read.

@Entity
@NamedQuery(name = “Book.findByTitle”, query = “SELECT b FROM Hibernate5Book b WHERE b.title = :title”)
@NamedQuery(name = “Book.findByPublishingDate”, query = “SELECT b FROM Hibernate5Book b WHERE b.publishingDate = :publishingDate”)
public class Book {
	...
}

Summary

The introduction of repeatable annotations in Java 8 fixed a general usability flaw. With version 2.2, you can finally benefit from it in the JPA specification. You no longer need to use any container annotations in your source code. You can now annotate your entities, methods, and attributes with multiple, repeatable annotations and the compiler will wrap them in a container annotation.

2 Comments

    1. Avatar photo Thorben Janssen says:

      JPA 2.2 is the current release. There have been a few discussions about the next release, but I’m not aware of any specific plans …

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.