Annotation Processing
About
Annotation Processing is a powerful feature in Java that allows developers to intercept and process annotations at compile time. It plays a vital role in code generation, validation, and automation of boilerplate tasks in large-scale applications and frameworks like Spring, Lombok, Dagger, etc.
Annotation processing is a compile-time mechanism that inspects the source code for annotations and can generate additional source files, perform validations, or create metadata.
It is handled by tools that implement the javax.annotation.processing.Processor interface (now jakarta.annotation.processing.Processor in Jakarta EE) and is integrated with the Java compiler (javac).
Annotation processors run during compilation and do not affect runtime behavior directly, but the code they generate or validate influences the final application.
When Is Annotation Processing Used ?
Annotation processing is used when:
We want to generate source code automatically (e.g., builder classes, DTOs, factories).
We want to validate annotation usage (e.g., checking constraints).
We want to generate configuration metadata (e.g., Spring factories, JSON schema, etc.).
We are building a framework or library that relies on compile-time structure.
Examples
Generate boilerplate code
Lombok
Dependency Injection
Dagger, Hilt
JSON Serialization
AutoValue, Gson, Jackson
Configuration Metadata
Spring Boot
Mapper Generation
MapStruct
How It Works ?
We create a custom annotation.
We implement an annotation processor that:
Identifies target annotations.
Uses the compiler’s Abstract Syntax Tree (AST) or Elements/Mirrors API.
Optionally generates new source files.
The annotation processor is registered using
META-INF/services/javax.annotation.processing.Processorfile.During compilation,
javacinvokes the processor, processes annotations, and generates code before final compilation completes.
Use Case: @AutoToString Annotation
We’ll create a custom annotation @AutoToString that, when applied to a class, generates a helper class with a toString() method implementation for that class.
This is a compile-time code generation example - the processor will generate code based on our annotation.
Folder Structure
Define the Annotation
@Target(TYPE)— used on classes@Retention(SOURCE)— we only care during compile time
Implement the Annotation Processor
It identifies all classes annotated with
@AutoToString.For each class, it generates a helper class like
PersonToStringGenerator.java.It creates a static method that builds a
toStringoutput using the class fields.
Register the Processor
Path: src/main/resources/META-INF/services/javax.annotation.processing.Processor
Contents:
This tells the compiler which class is an annotation processor.
Use the Annotation in a Client Class
When this is compiled, the processor generates:
Use the Generated Code
Build the JAR using Maven
1. Add pom.xml
pom.xmlHere is a basic Maven config
No dependencies are needed unless we use external libraries in our processor.
2. Package the JAR
Run this from inside our project folder
This will generate a JAR in
That JAR will contain
Our processor class
The
@AutoToStringannotationThe
META-INF/services/javax.annotation.processing.Processorfile
Use the JAR in Another Project
Now in our actual project (say, where Person.java is):
Put the above JAR in the classpath
Compile with:
This will trigger our annotation processor during compilation.
Use the JAR in Maven Project
In our main project's pom.xml, we can declare the processor as a build-time dependency only:
And for automatic annotation processing:
Last updated