Summary - Annotation
- Java course
- Advanced
- Lesson 36/82
- 5 min
Combine @interface and @Retention to write a marking framework.
Summary - Annotations
In this group we learned annotations: defining with @interface, controlling behavior with @Retention and @Target, elements and default values, and reading with reflection. Now we bring them together.
Built-in annotations give the compiler hints, while our own let frameworks discover classes automatically. To read an annotation at runtime RUNTIME retention is required. Now we look at the last feature: repeatable annotations.
Repeatable annotations
Normally an annotation cannot be applied twice to the same element. The @Repeatable meta-annotation removes this limit, but you must define a container annotation.
The container is an annotation holding an array of the repeatable one: @interface Roles { Role[] value(); }. The repeatable annotation is marked @Repeatable(Roles.class). Then @Role("admin") @Role("editor") can be applied twice; reflection with getAnnotationsByType(Role.class) returns both.
Practice Count the repeatable Role annotation
Define an @interface Role with String value(), marked @Repeatable(Roles.class), @Retention(RUNTIME), @Target(TYPE). Define a container @interface Roles with Role[] value(), marked @Retention(RUNTIME) @Target(TYPE). Apply @Role("admin") and @Role("editor") to the User class. In main, print getAnnotationsByType(Role.class).length with System.out.println.
Starter code
// Define the Role annotation and Roles container
// Add two Role markers to the User class
// Print the count in mainSample solution
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Repeatable(Roles.class)
@interface Role { String value(); }
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Roles { Role[] value(); }
@Role("admin")
@Role("editor")
class User { }
public class RoleCount {
public static void main(String[] args) {
int n = User.class.getAnnotationsByType(Role.class).length;
System.out.println(n);
}
}Expected output
2
Practice Check and read the Version annotation
Define an @interface Version with int value(), marked @Retention(RetentionPolicy.RUNTIME) and @Target(ElementType.TYPE). Apply @Version(3) to the App class. In main, first print its presence with isAnnotationPresent, then its value with getAnnotation, both via System.out.println.
Starter code
// Define the Version annotation (RUNTIME, TYPE)
// Apply Version to the App class
// Print presence and value in mainSample solution
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Version { int value(); }
@Version(3)
class App { }
public class VersionCheck {
public static void main(String[] args) {
System.out.println(App.class.isAnnotationPresent(Version.class));
System.out.println(App.class.getAnnotation(Version.class).value());
}
}Expected output
true 3
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 Which retention is required to read an annotation with reflection?
- RetentionPolicy.SOURCE
- RetentionPolicy.CLASS
- ElementType.METHOD
- RetentionPolicy.RUNTIME Correct answer
Explanation: RUNTIME annotations are read by reflection.
2 Complete the @Repeatable definition
@Repeatable(____.class)
@Repeatable(Roles.class)
Explanation: The container annotation class is given.