Understanding Java Annotations: Definition, Essence, Details, and Parsing SOURCE‑Retention Annotations
This article explains what Java annotations are, their underlying nature as interfaces extending Annotation, the various meta‑annotations such as @Retention and @Target, how retention policies affect availability, and demonstrates how to parse SOURCE‑retention annotations using a custom AbstractProcessor with complete code examples.
In Java development you often see @xxx placed on classes or methods; this is called an annotation . The article starts with a simple test method and shows the custom annotation @MyRequiredArgsConstructor and its usage on a class ExamplePo .
What Is an Annotation
Annotations provide extra information to the compiler and can be applied to classes, methods, fields, parameters, etc. They act like tags that tell the compiler to perform specific actions during compilation or runtime.
The Essence of Annotations
An annotation is essentially an @interface which, after compilation, becomes a regular interface that extends java.lang.annotation.Annotation . The example shows the compiled form of MyRequiredArgsConstructor and how the @interface is transformed.
Annotation Details
Annotations are read by the compiler; if the compiler does not process them they are meaningless. They can be retained at different stages:
RetentionPolicy.SOURCE : kept only in source code.
RetentionPolicy.CLASS : kept in the compiled class file.
RetentionPolicy.RUNTIME : available at runtime via reflection.
The @Target meta‑annotation restricts where an annotation can be placed (e.g., TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE).
Meta‑Annotations
Common meta‑annotations include @Retention , @Target , @Documented , and @Inherited , which control lifecycle, scope, documentation, and inheritance of annotations.
Parsing SOURCE‑Retention Annotations
Because SOURCE annotations disappear after compilation, they cannot be accessed via reflection. The article provides a custom annotation processor that extends AbstractProcessor to read such annotations at compile time. The processor scans elements annotated with MyRequiredArgsConstructor , reflects on the class, and generates a constructor that includes all final or annotated fields.
@SupportedAnnotationTypes("com.example.annotation.MyRequiredArgsConstructor")
@Slf4j
public class SourceAnnotationProcessor extends AbstractProcessor {
@Override
public boolean process(Set
annotations, RoundEnvironment roundEnv) {
for (Element element : roundEnv.getElementsAnnotatedWith(MyRequiredArgsConstructor.class)) {
Name qualifiedName = ((TypeElement) element).getQualifiedName();
Class clazz = null;
try { clazz = Class.forName(qualifiedName.toString()); }
catch (ClassNotFoundException e) { throw new RuntimeException(e); }
// generate constructor code based on fields and annotation attributes
// ... (code omitted for brevity)
log.info("generated ExamplePo Construct: \n [{}]", constructor);
}
return true;
}
}A test method demonstrates how to invoke the Java Compiler API, register the processor, and compile a source file, producing the generated constructor.
@Test
public void testAnnotationDemo() {
// pseudo‑code to compile ExamplePo.java with the custom processor
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
Iterable
compilationUnits = fileManager.getJavaFileObjectsFromFiles(
Arrays.asList(new File("src/test/java/com/example/ExamplePo.java")));
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, null, null, compilationUnits);
task.setProcessors(Arrays.asList(new SourceAnnotationProcessor()));
task.call();
}The output shows that the processor successfully detected the annotation and generated the corresponding constructor.
Conclusion
If an annotation uses @Retention(SOURCE) , it is unavailable at runtime; to access it you must either change the retention to CLASS or RUNTIME , or use a compile‑time processor as demonstrated. Alternatively, bytecode manipulation tools like ASM or Byte Buddy can embed source‑level annotation data into the class file.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
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.