Meta-annotations: @Retention, @Target, @Documented, @Inherited, @Repeatable
Annotations that annotate annotation declarations — and the critical RUNTIME retention trap.
Meta-annotations
Meta-annotations are annotations applied to annotation declarations themselves. They configure how the annotation is stored, where it can be used, and how it behaves.
@Retention — where the annotation lives
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Audited {}
| Policy | Annotation survives to... |
|---|---|
| SOURCE | Compile-time only — stripped from .class file. Lombok, @Override |
| CLASS | .class file — default if omitted, but not available at runtime |
| RUNTIME | JVM at runtime — readable via reflection |
RUNTIME is the only policy that lets reflection read the annotation. Frameworks like Spring and JUnit require RUNTIME; annotation processors (like Lombok) use SOURCE.
@Target — where the annotation can be applied
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
@Target({ElementType.METHOD, ElementType.FIELD})
public @interface Validate {}
Common ElementType values: TYPE (class/interface/enum), FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE.
Without @Target, the annotation can be applied to almost any element. With @Target, the compiler enforces the restriction.
@Documented
@Documented
public @interface PublicApi {}
Annotated elements show the annotation in generated Javadoc. Without @Documented, annotations are invisible in the API docs.
@Inherited
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface Category { String value(); }
If a class is annotated with @Category, its subclasses automatically inherit the annotation. @Inherited applies only to class-level annotations — it has no effect on methods or fields.
@Repeatable
@Repeatable(Tags.class)
public @interface Tag { String value(); }
public @interface Tags { Tag[] value(); } // container annotation
@Tag("fast")
@Tag("reviewed")
public void process() {}
Without @Repeatable, applying the same annotation twice is a compile error. @Repeatable requires a container annotation whose value() element is an array of the repeatable annotation.