Repeating Annotations in Java 8

Java 8 has introduced a new Java programming language feature, repeating/repeated annotations. Prior to Java 8, only one annotation of a particular annotation type could annotate a Java construct. Java 8 has made it feasible to annotate a Java construct with multiple annotations of a single annotation type.

As a primer, annotation types are used in conjunction with annotations to define metadata. Annotation types may be divided into three kinds: marker annotation type, single element annotation type, and complex annotation type as shown in Figure 1.

Repeat1
Figure 1: Annotation types

Annotation type declarations are similar to normal interface declarations with some differences. Annotation types are declared with @interface instead of the keyword interface. Annotation types declare annotation type element declarations, which are similar in syntax to abstract method declarations. Annotation type element declarations may declare a default value using the default keyword. An annotation type declaration that does not include any annotation type element declarations is called a marker annotation type. A single element annotation type declaration has only a single element. Although any element name may be specified, by convention the value element is the only element in a single element annotation type declaration. A complex annotation type typically declares one or more elements other than the value element. An annotation type declares a type that may be used to annotate different program elements.

The annotations are used only to associate information, also called metadata, with the annotated program constructs such as methods and declarations, and do not affect the code logic. The information associated with a program element is specified in the annotation type elements using name/value pairs. An annotation must specify a name/value pair for every element in the annotation type that does not have a default value.

Java 8 has added support for repeating annotations. In this article, first we shall demonstrate the need for repeating annotations and subsequently demonstrate the use of repeating annotations in JDK 8.

Setting the Environment

To test the repeating annotations we need to install Java 8, preferably a Java IDE with support for Java 8. Eclipse LUNA supports Java 8. Download and install JDK 7 and JDK 8. Create an Eclipse project, RepeatingAnnotations, for example. For the Before-example, which we shall discuss next, set JDK Compliance level to 1.7. For the After-example, set the JDK compliance level to 1.8 as shown in Figure 2.

Repeat2
Figure 2: Setting the JDK compliance level to 1.8

Single Annotations in Java 7

Create an annotation type called Punchcard with two annotation type elements, startTime and endTime, of type String to record the start time and end time for a punchcard. Set the default value of the annotation type elements to an empty String "".

package jdk7;


public @interface Punchcard {
   String startTime() default "";
   String endTime() default "";


}

Create a Java class, PunchCardImpl, to demonstrate the need for repeating annotations. Add a method called setPunchCard() and annotate the method with the @Punchcard annotation twice, once to record the start time and once to record the end time.

package jdk7;

public class PunchCardImpl {

   @Punchcard(startTime="10 AM")
   @Punchcard(endTime="4 PM")



   public void setPunchCard(){
   }

}

With the Java Compiler and JDK Compliance level set to JDK 7, the two repeating annotations of @Punchcard generate a compiler error: "Duplicate annotation @Punchcard. Repeated annotations are allowed only at source level 1.8 or above," as shown in Figure 3.

Repeat3
Figure 3: Duplicate annotations throw an error

To avoid the Duplicate annotation, we would need an alternative, such as to define two annotations types of PunchcardStartTime to record the start time and PunchcardEndTime to record the end time for a punchcard. The PunchcardStartTime has only one annotation type element, startTime; and PunchcardEndTime has one annotation type element, endTime.

package jdk7;

public @interface PunchcardStartTime {

   String startTime() default "";

}

package jdk7;

public @interface PunchcardEndTime {
   String endTime() default "";
}

In the implementation class, PunchCardImpl used to test the annotation types. We need to annotate the setPunchCard method with the @PunchcardStartTime annotation to record the start time and with the @PunchcardEndTime annotation to record the end time.

public class PunchCardImpl {

   @PunchcardStartTime(startTime="10 AM")
   @PunchcardEndTime(endTime="4 PM")

   public void setPunchCard(){
   }

}

With the @PunchcardStartTime and @PunchcardEndTime annotations replacing two @Punchcard annotations, the "Duplicate Annotations" exception is removed, as shown in Figure 4.

Repeat4
Figure 4: Removing the "Duplicate Annotations" exception

We had to create two annotation types and annotate the method with annotations for both the annotation types.

Repeatable Annotations in Java 8

Java 8 has introduced an annotation type called java.lang.annotation.Repeatable, which may be used to annotate another annotation type to indicate that the annotation type is repeatable, implying that multiple annotations for the annotation type may annotate the same Java construct. The value of the @Repeatable annotation indicates the containing annotation type for the repeatable annotation type.

We shall use the same example of a punchcard to demonstrate the use of repeating annotations. Create an annotation type of Punchcard as before, but annotate the annotation type declaration with @Repeatable and specify a containing annotation type, PunchCards.class, for the repeatable annotation type Punchcard. A containing annotation type for a repeatable annotation type is required to use the repeatable annotation type in repeating annotations.

package jdk8;

import java.lang.annotation.Repeatable;

@Repeatable(PunchCards.class)
public @interface Punchcard {
   String startTime() default "";
   String endTime() default "";




}

Next, create the containing annotation type PunchCards and add a annotation type element of the type of an array of the repeatable annotation type Punchcard.

package jdk8;

@interface PunchCards {
   Punchcard[] value();

}

Next, to demonstrate the use of the repeatable annotation type Punchcard, create the same PunchCardImpl class that generated a Duplicate Annotation error with the Before-example. The setPunchCard method is annotated twice with the @Punchcard annotation, once with a value for the startTime annotation element and once with a value for the endTime annotation element. As the annotation type declaration, Punchcard specifies default values for the annotation type elements; we don't need to specify a value for both startTime and endTime in the same annotation.

package jdk8;

public class PunchCardImpl {

   @Punchcard(startTime="10 AM")
   @Punchcard(endTime="4 PM")

   public void setPunchCard(){
   }

}

With the project JRE set to JDK 8 and the JDK Compliance level set to JDK 8 also, the PunchCardImpl does not generate a compiler error, as shown in Figure 5.

Repeat5
Figure 5: A compiler error is not generated

Conclusion

In this article, we demonstrated the need and the use of repeating/repeated annotations, a new Java programming language feature in JDK 8.

About | Sitemap | Contact