Meta Annotation
Overview of meta-annotation in Java.
About
In Java, meta-annotations are annotations that apply to other annotations. They define how custom annotations behave and are an essential part of building a clean, consistent annotation-based system in any Java application or framework.
Just like classes can be described by annotations, annotations themselves can also be described—this is what meta-annotations are for.
Why Meta-Annotations?
When creating custom annotations, we often need to define:
Where it can be applied (e.g., on methods, classes, fields)
How long it should be retained (e.g., only in source code or also at runtime)
Whether it should be inherited
Whether it can be repeated
Whether it should appear in the generated Javadocs
These aspects are controlled using meta-annotations.
Available Meta-Annotations in Java
Java provides five core meta-annotations in the java.lang.annotation
package
@Target
Specifies where the annotation can be applied.
@Retention
Defines how long the annotation is retained (source, class, or runtime).
@Inherited
Allows the annotation to be inherited by subclasses.
@Documented
Marks the annotation to be included in Javadocs.
@Repeatable
Allows an annotation to be applied multiple times to the same element.
@Target
@Target
Specifies the valid locations (or elements) where the annotation can be used, such as methods, fields, constructors, parameters, etc.
@Target(ElementType.METHOD)
public @interface MyAnnotation {}
Possible ElementType
values
ElementType
valuesTYPE
Class, interface, or enum
FIELD
Fields (instance variables)
METHOD
Methods
PARAMETER
Method parameters
CONSTRUCTOR
Constructors
LOCAL_VARIABLE
Local variables inside methods
ANNOTATION_TYPE
Other annotations
PACKAGE
Java packages
TYPE_USE
Any use of a type (generics, casts, etc.)
MODULE
Java 9 modules
Example
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface AuditLog {}
@Retention
@Retention
Defines how long the annotation is retained in the program lifecycle.
@Retention(RetentionPolicy.RUNTIME)
public @interface Loggable {}
Retention policies
SOURCE
Available only in source code. Removed during compilation.
CLASS
Present in the .class
file but not accessible at runtime via reflection.
RUNTIME
Present in the .class
file and available via reflection at runtime.
Example
@Retention(RetentionPolicy.CLASS)
public @interface CompileOnly {}
@Inherited
@Inherited
Specifies that if a class is annotated, then its subclasses will automatically inherit the annotation.
Note: This only applies to class-level annotations, not methods or fields.
@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Secured {}
@Secured
public class BaseService {}
public class UserService extends BaseService {}
Here, UserService
will be treated as if it has @Secured
even though it is not explicitly annotated.
@Documented
@Documented
Indicates that the annotation should be included in the generated Javadoc.
Without this, annotations are not visible in Javadoc output by default.
@Documented
@Target(ElementType.METHOD)
public @interface DeveloperNote {
String value();
}
@Repeatable
@Repeatable
Allows the same annotation to be used multiple times on the same element.
Prior to Java 8, an annotation could be applied only once on a target.
How it works ?
We must define a container annotation to hold the repeated annotations.
// Repeatable annotation
@Repeatable(Schedules.class)
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Schedule {
String day();
}
// Container annotation
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Schedules {
Schedule[] value();
}
Usage
@Schedule(day = "Monday")
@Schedule(day = "Friday")
public void generateReport() {}
With Repeatable, we can apply the same annotation multiple times to the same element. Java will group these annotations into a container annotation (which we define). We (or the framework we use) are responsible for checking all the annotations and acting on them.
If we want some logic to execute based on each annotation, we must write code to loop through the annotations:
Method method = MyClass.class.getMethod("generateReport");
Schedule[] schedules = method.getAnnotationsByType(Schedule.class);
for (Schedule schedule : schedules) {
System.out.println("Execute logic for: " + schedule.day());
}
Last updated