До появления Java 8 при использовании аннотаций часто возникали проблемы, если необходимо было применить к классу, интерфейсу или полю одну и ту же аннотацию несколько раз. Например, предположим, что мы хотим описать через JPA сущность Студент с двумя NamedQuery. Чтобы обойти эту проблему (до JPA 2.2) необходимо было использовать дополнительную аннотацию (javax.persistence.@NamedQueries):
@Entity
@NamedQueries({
@NamedQuery(name = “Student.findByName”, query = “SELECT s FROM Student s WHERE s.name = :name”),
@NamedQuery(name = “Student.findByGroup”, query = “SELECT s FROM Student s WHERE s.group = :group”)
})
public class Student implements Serializable {
//implementation
}
В Java 8 появилась поддержка повторяемых аннотаций.
Чтобы определить повторяемую аннотацию, необходимо пометить ее определение мета-аннотацией:
import java.lang.annotation.Repeatable;
@Repeatable(Queries.class)
public @interface Query {
String name() default "someName";
}
@Queries - аннотация-контейнер, для хранения повторяющихся аннотаций. Определение аннотации-контейнера должно содержать value с типом массива необходимой аннотации. Для Query аннотация @Queries может быть определена следующим образом:
public @interface Queries {
Query[] value();
}
Теперь (начиная с JPA 2.2) пример с сущностью Student можно переписать следующим образом:
@Entity
@NamedQuery(name = “Student.findByName”, query = “SELECT s FROM Student s WHERE s.name = :name”),
@NamedQuery(name = “Student.findByGroup”, query = “SELECT s FROM Student s WHERE s.group = :group”)
public class Student implements Serializable {
//implementation
}
Это можно сделать благодаря тому, что в JPA 2.2 определение NamedQuery помечено мета-аннотацией @Repeatable:
@Repeatable(NamedQueries.class)
@Target({TYPE})
@Retention(RUNTIME)
public @interface NamedQuery { //implementation }