Annotation Processing at Compile Time and Runtime
Fast recall
Quick revision
Core answer
Whether you understand the @Retention policy (SOURCE vs CLASS vs RUNTIME) and the difference between compile-time code generation and runtime introspection.
Forgetting that @Retention(RetentionPolicy.SOURCE) annotations are discarded after javac — you cannot read them at runtime.
Discuss how Lombok hooks into javac via internal APIs to mutate the AST directly (not the public Processor API), and why this makes Lombok fragile across JDK versions.
Interview-ready guide
Interview answer
Annotation processing has two distinct modes — compile-time processing that generates code during the build, and runtime processing that reads annotations from loaded classes.
Compile-time processing (APT):
- Implement
AbstractProcessor— javac feeds annotated elements in rounds; your processor generates new source files - Can generate new files; cannot modify existing source code (standard JSR-269 constraint)
- Used by: MapStruct (mapper implementations), Dagger (injection factories)
Runtime processing:
- Uses
java.lang.reflectto read annotations from loaded classes - Used by: Spring (
@Component/@Autowired), Hibernate (@Entity), Jackson (@JsonProperty) - Spring caches all annotations at startup in
BeanDefinitionobjects — hot path never re-reads annotations
@Retention policy:
SOURCE: compile-time hints only (e.g.@Override) — discarded after compilationRUNTIME: readable via reflection — frameworks need this to discover annotated classes at runtimeCLASS: stays in bytecode for bytecode analyzers; not loaded by the JVM's reflection API
Lombok gotcha:
- Hooks into private javac APIs to modify the AST directly — looks like APT but isn't standard
- Breaks on JDK upgrades; standard processors like MapStruct don't
I recommend JSR-269 processors for code generation and RUNTIME annotations for framework integration.
Annotation Processing at Compile Time and Runtime
Direct Answer
Java has two annotation processing modes: compile-time via the Annotation Processing API (javax.annotation.processing), where Processor subclasses generate source or validate code during javac; and runtime via reflection (element.getAnnotation()), which reads retained annotations from bytecode. Compile-time processing is used by Lombok, MapStruct, and Dagger; runtime processing by Spring, Jackson, and Hibernate.
Common Mistakes & Pitfalls
Forgetting that @Retention(RetentionPolicy.SOURCE) annotations are discarded after javac — you cannot read them at runtime.
Check your understanding
Answer these without looking back at the article.
- How does Lombok differ from a standard Annotation Processor?
- What is the difference between APT and reflection-based frameworks like Spring?
- How would you write a custom compile-time validator using Annotation Processing?
Related interview prep categories
2Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.