Custom Annotations

Declaring an Annotation

Use @interface. Two meta-annotations decide how it behaves:

Meta-annotationValues
@RetentionSOURCE (dropped by compiler, e.g. Lombok), CLASS (in .class, not at runtime — default), RUNTIME (readable with reflection)
@TargetTYPE, METHOD, FIELD, PARAMETER, CONSTRUCTOR, RECORD_COMPONENT...
@Inheritedsubclasses inherit the class annotation
@Repeatableallow the same annotation more than once
@Documentedinclude in Javadoc

Elements and Defaults

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RateLimit {
    int requestsPerMinute() default 60;   // element with a default
    String key() default "ip";
}

// usage
@RateLimit(requestsPerMinute = 5, key = "userId")
public OtpResponse sendOtp(String phone) { ... }

// an annotation with a single element named value() can be written without the name
public @interface Role { String value(); }
@Role("ADMIN") void deleteUser(long id) { ... }

Note: Element types are limited to primitives, String, Class, enums, other annotations and arrays of these.