Repeatable and type annotations

Java 8 Course · lesson 14 of 16 · 3 min read

Java 8 let annotations repeat, and let them appear anywhere a type does.

Open this lesson in the learning hub

Key points

  • Before 8, applying the same annotation twice needed a hand-written container annotation.
  • @Repeatable lets the compiler generate that wrapping for you.
  • Type annotations can sit on any type use - List<@NonNull String>, casts, throws clauses.
  • The JDK ships no null checker; type annotations exist so tools like the Checker Framework can.
  • Only RUNTIME retention survives into a form reflection can read.

Example

import java.lang.annotation.*;
import java.util.*;

public class Main {
    @Retention(RetentionPolicy.RUNTIME)
    @Repeatable(Roles.class)
    @interface Role { String value(); }

    @Retention(RetentionPolicy.RUNTIME)
    @interface Roles { Role[] value(); }

    @Role("admin")
    @Role("auditor")
    static class Account { }

    public static void main(String[] args) {
        Role[] roles = Account.class.getAnnotationsByType(Role.class);
        System.out.println("repeated annotations found: " + roles.length);
        for (Role r : roles) {
            System.out.println("  role = " + r.value());
        }
        // The container is generated for you
        System.out.println("container   : " + Account.class.getAnnotation(Roles.class));
    }
}

@Repeatable is compiler sugar over a container annotation - reflection still sees the wrapper.

This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Java 8 Course course, and every lesson in it is listed on the Java 8 Course contents page.