Understanding Java Annotations and Meta‑Annotations: Principles, Built‑in Annotations, and Custom Annotation Creation
This article explains the purpose and mechanics of Java annotations introduced in JDK 5, describes the five standard annotations, details the four meta‑annotations (@Target, @Retention, @Inherited, @Documented), and provides step‑by‑step guidance on defining, using, and processing custom annotations with reflection.
All Java developers in China know that mainstream project architectures such as SSM, SSH, and Spring Cloud rely heavily on Spring, which uses a large number of annotations (including Spring‑specific ones). To use annotations effectively, one must understand the principles and basic usage of Java annotations.
JDK 5.0 introduced several impactful features, including enums, autoboxing/unboxing, generics, and annotations. Annotations were added to provide metadata support.
An annotation is an interface; programs can obtain an Annotation object for a given program element via reflection and retrieve the metadata stored in the annotation. Annotations do not affect program execution unless a tool (such as an Annotation Processing Tool) processes them.
JDK 5 also supplies five basic annotations:
@Override – forces a method to override a superclass method. @Deprecated – marks a class or method as outdated. @SuppressWarnings – suppresses compiler warnings. @SafeVarargs – suppresses heap‑pollution warnings for varargs. @FunctionalInterface – indicates that an interface is a functional interface (contains exactly one abstract method).
These built‑in annotations mainly provide compile‑time checks and do not change runtime behavior. Spring, however, introduces many more annotations that simplify repetitive coding tasks.
To create custom annotations, you first need to understand Java’s meta‑annotations, which are annotations that annotate other annotations.
Java defines four standard meta‑annotations: @Target – specifies the kinds of program elements an annotation can be applied to. @Retention – defines how long the annotation is retained (SOURCE, CLASS, or RUNTIME). @Inherited – indicates that an annotation is inherited by subclasses. @Documented – signals that the annotation should be included in Javadoc.
@Target
Purpose: Marks the applicable element types for an annotation.
Possible ElementType values:
CONSTRUCTOR – constructors FIELD – member variables LOCAL_VARIABLE – local variables METHOD – ordinary methods PACKAGE – packages PARAMETER – parameters TYPE – classes, interfaces, enums, annotation types ANNOTATION_TYPE – other annotations
Example:
@Target(ElementType.FIELD)
public @interface TargetTest6 {}
@Target({ElementType.TYPE_PARAMETER, ElementType.METHOD})
public @interface TargetTest7 {}@Retention
Specifies how long the annotation is retained:
SOURCE – discarded by the compiler. CLASS – stored in the .class file but not available at runtime. RUNTIME – retained at runtime and accessible via reflection.
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TargetTest6 {}@Inherited
When an annotation is marked with @Inherited, subclasses automatically inherit the annotation from their superclass.
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface TargetTest6 {}
// All classes annotated with @TargetTest6 will have the annotation inherited by subclasses.@Documented
Indicates that the annotation should be included in generated Javadoc.
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface TargetTest6 {}
// Javadoc will contain information about @TargetTest6.With these meta‑annotations, you can define custom annotations. The syntax is similar to an interface:
public @interface MyAnnotation {
// member variables are defined as parameter‑less methods
String name();
int age();
}Example custom annotation with @Target and @Retention:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnonTest {
int age();
String name();
}Usage (values must be supplied unless defaults are defined):
public class Test {
@AnonTest(age = 0, name = "1")
public Integer tes;
}If a member has a default value, the value can be omitted:
@Target(ElementType.FIELD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface AnonTest {
int age() default 1;
String name() default "annotation default";
} public class Test {
@AnonTest // uses default values
public Integer tes;
}Annotations themselves do not execute code; you must retrieve and process them. Java provides the Annotation interface and the AnnotatedElement interface with methods such as getAnnotation, getAnnotations, isAnnotationPresent, and getDeclaredAnnotations.
Class – class definition Constructor – constructor definition Field – field definition Method – method definition Package – package definition
Example of extracting annotations via reflection:
@Component
@Service
public class Test {
@AnonTest
public Integer tes;
@Deprecated
public void m1() {}
public static void main(String[] args) {
try {
Annotation[] classAnnotations = Class.forName("com.anon.test").getAnnotations();
Annotation[] methodAnnotations = Class.forName("com.anon.test").getMethod("m1").getAnnotations();
for (Annotation a : classAnnotations) {
System.out.println(a.getClass());
if (a instanceof Component) {
System.out.println("Found annotation:" + a);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}Processing a custom annotation on fields:
public static void getInfo(Class
clazz) {
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(AnonTest.class)) {
AnonTest anon = field.getAnnotation(AnonTest.class);
System.out.println("Name: " + anon.name());
System.out.println("Age: " + anon.age());
System.out.println("Report to user age distribution table");
}
}
}Running the above code produces:
1. Name is: 张小龙
2. Age is: 25
3. Report to user age distribution tableIn summary, annotations are a supplemental mechanism in Java that do not affect program execution by themselves, but when used wisely they can greatly improve development efficiency and code standardization.
Java Captain
Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.