JPA 2.2 Introduces @Repeatable Annotations

By Thorben Janssen

Mapping

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.

Annotation Description
AssociationOverride Override the mapping for an entity relationship.
AttributeOverride Override the mapping of a Basic property.
Convert Activates or deactivates an AttributeConverter for a Basic property.
JoinColumn Defines a join column for an association or element collection.
MapKeyJoinColumn Defines the mapping to an entity that’s used as the map key.
NamedEntityGraph Specifies a graph of entities that are fetched with a query.
NamedNativeQuery Defines a named native SQL query.
NamedQuery Defines a named JPQL query.
NamedStoredProcedureQuery Defines a named stored procedure query.
PersistenceContext References a container-managed EntityManager.
PersistenceUnit References a EntityManagerFactory and its associated persistence unit.
PrimaryKeyJoinColumn References a primary key column that’s used as a foreign key to join to another table.
SecondaryTable Defines a secondary database table that’s mapped by the entity.
SqlResultSetMapping Defines the mapping of the result of native SQL query.
SequenceGenerator Defines the sequence based primary key generator that’s referenced by a GeneratedValue annotation.
TableGenerator Defines 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.


Tags

Mapping


About the author

Thorben is an independent consultant, international speaker, and trainer specialized in solving Java persistence problems with JPA and Hibernate.
He is also the author of Amazon’s bestselling book Hibernate Tips - More than 70 solutions to common Hibernate problems.

Books and Courses

Coaching and Consulting

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.

    1. 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 …

{"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}