CodeBlanks Logo Icon CodeBlanks

Summary - Annotation

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

Main.java
// Define the Role annotation and Roles container
// Add two Role markers to the User class
// Print the count in main

Sample solution

Main.java
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

Main.java
// Define the Version annotation (RUNTIME, TYPE)
// Apply Version to the App class
// Print presence and value in main

Sample solution

Main.java
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

Question
@Repeatable(____.class)
Answer
@Repeatable(Roles.class)

Explanation: The container annotation class is given.

All lessons in Advanced