Meta-Annotations in Java β <code>@Retention</code>, <code>@Target</code> and Friends
A meta-annotation is an annotation applied to another annotation. Java's five meta-annotations in java.lang.annotation control where and how long your custom annotations exist, and how they relate to inheritance.
The five meta-annotations
| Meta-annotation | Controls |
|---|---|
@Retention | How long the annotation is kept β SOURCE, CLASS, or RUNTIME |
@Target | Which program elements it can be applied to |
@Inherited | Whether subclasses inherit a class-level annotation |
@Documented | Whether Javadoc includes the annotation |
@Repeatable | Whether the annotation can appear multiple times on the same element |
@Retention β three policies
@Retention(RetentionPolicy.SOURCE) // compiler only, discarded after (@Override, lint)
@Retention(RetentionPolicy.CLASS) // in bytecode but not loaded by reflection (default)
@Retention(RetentionPolicy.RUNTIME) // available via reflection β most common for frameworks
@Target β where the annotation can appear
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface MyAnno { ... }
| ElementType | Location |
|---|---|
TYPE | Classes, interfaces, enums, records, annotations |
FIELD | Fields |
METHOD | Methods |
PARAMETER | Method / constructor parameters |
CONSTRUCTOR | Constructors |
LOCAL_VARIABLE | Local variables (rarely useful at runtime) |
ANNOTATION_TYPE | Other annotations (meta-annotations) |
PACKAGE | Package declarations |
TYPE_PARAMETER | Type parameters β <@NotNull T> |
TYPE_USE | Any type use β List<@NotNull String> |
MODULE | Module declarations |
@Inherited
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Service {}
@Service
public class BaseService { ... }
public class UserService extends BaseService {}
UserService.class.getAnnotation(Service.class); // non-null β inherited
Only works on class-level annotations. Doesn't affect interfaces or methods.
@Documented
Adds the annotation to the generated Javadoc of the annotated element. Useful for framework annotations that callers need to see in API documentation.
@Repeatable (Java 8+)
@Repeatable(Schedules.class)
public @interface Schedule {
String dayOfMonth();
String dayOfWeek() default "*";
}
public @interface Schedules {
Schedule[] value(); // "container" annotation
}
@Schedule(dayOfMonth = "1")
@Schedule(dayOfMonth = "15")
public void runTwiceAMonth() { ... }
A realistic template
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RateLimit {
int permits();
long periodSeconds();
boolean perUser() default false;
}
Common mistakes
- No
@Retentionβ defaults toCLASS, so reflection can't see it. - No
@Targetβ the annotation can be placed anywhere, including useless spots. - Using
@Inheritedon a method annotation β it only works on type annotations. - Forgetting the container annotation for
@Repeatableβ the compiler tells you, but the error is easy to misread.
Related
Pillar: Java annotations. Siblings: writing custom annotations.