What is annotation processing (APT) in Java, and what can and cannot a processor do during compilation?
answer
- Compiler plugin, runs at compile time
- Can only ADD new files (Filer), never edit existing source
- Generated files re-processed in later rounds
- Diagnostics via Messager can fail the build
- Lombok is the AST-mutating exception, not normal APT
basics
~10 sAnnotation processing is a hook in the Java compiler that runs your code during compilation. It reads annotations in the source, and can generate brand-new source files. It cannot change existing files.
solid answer
~40 sAnnotation processing (APT) is a compiler plugin mechanism, part of javac, that lets you run code at compile time. The compiler discovers Processor implementations, hands them the annotated program elements, and lets them inspect the code's structure and emit diagnostics or generate new files. The golden rule is that a processor can only create new source or resource files (via the Filer); it cannot modify or delete existing source files. Generated files are themselves fed back through another processing round so their annotations get processed too. This is how Dagger, MapStruct, and AutoValue produce boilerplate at compile time with zero runtime reflection cost. Lombok is the well-known exception: it abuses internal compiler APIs to mutate the AST of existing classes, which is not standard APT behavior.
go deeper
Knows APT runs at compile time and generates new code from annotations; can name a tool like Lombok or a builder generator.
States the can-add/cannot-modify rule, knows files are generated via the Filer and re-processed in rounds, and can distinguish APT from runtime reflection.
Explains the round model, the additive constraint and why it exists, the Messager-fails-build behavior, and that Lombok is an AST-hack exception.
Can reason about build-tooling tradeoffs (compile-time generation vs reflection vs bytecode weaving), incremental-compilation implications, and why the additive constraint matters for tooling correctness.
## What problem does this solve? In Java you often need *boilerplate*: equals/hashCode, builders, dependency-injection wiring, DTO mappers. Writing it by hand is error-prone; generating it at **runtime** with reflection is slow and hides errors until the program runs. **Annotation processing** lets a build step generate that code at **compile time**, so it is type-checked, fast, and visible. ## Key terms (defined from scratch) - **Annotation**: metadata you attach to code, e.g. `@Override`, `@Entity`, or a custom `@AutoValue`. It does nothing by itself; something must *read* it. - **javac**: the standard Java compiler. - **APT (Annotation Processing Tool)**: historically a separate tool; since Java 6 it is built into javac. It is the phase where javac discovers and runs *annotation processors*. - **Annotation processor**: a class you write that implements the `javax.annotation.processing.Processor` interface (usually by extending `AbstractProcessor`). The compiler instantiates it and calls it. - **Round**: processing happens in repeated passes. Each pass is a **round**. If round 1 generates new source files, the compiler runs another round so those new files are also analyzed and their annotations processed. This continues until a round produces no new files. - **Filer**: the API a processor uses to *write* new files (source `.java`, class files, or arbitrary resources). It is the only sanctioned way to output. ## What a processor CAN do 1. **Inspect** the structure of the code being compiled — classes, methods, fields, their modifiers, types, and the annotations on them — through the *element model* (see other questions). 2. **Generate new files** via the `Filer`: most commonly new `.java` source files. Those new files are compiled and re-processed in later rounds. 3. **Report diagnostics** via the `Messager` — notes, warnings, and *errors that fail the build*. This is how a processor enforces rules (e.g. "@AutoValue must be on an abstract class"). ## What a processor CANNOT do (the golden rule) A standard processor **cannot modify or delete existing source files**. APT is purely *additive*. You cannot, in standard APT, add a method to an existing class or rewrite a method body. This constraint is deliberate: it keeps the source you wrote authoritative and the generation predictable. - This is exactly why frameworks generate a *new* class (e.g. `AutoValue_Foo extends Foo`, `FooMapperImpl implements FooMapper`) instead of editing yours. - **Lombok** appears to violate this — `@Getter` really does add methods *to your class*. It does so by reaching into javac's internal AST (abstract syntax tree) APIs, which is unsupported, version-fragile hackery, not normal annotation processing. ## How it runs in the build During compilation javac looks on the classpath/processor-path for registered processors (via `META-INF/services/javax.annotation.processing.Processor`), instantiates each, calls `init`, then calls `process` once per round. You can disable processing entirely with `-proc:none`, run *only* processing with `-proc:only`, or name processors explicitly with `-processor`. ## Why it matters Compile-time generation gives you reflection-free, type-safe boilerplate: Dagger wires DI graphs, MapStruct writes mappers, AutoValue/Immutables write value classes — all checked by the compiler and with no runtime startup cost.
- Why can't a processor edit an existing source file, and how do frameworks work around it?APT is intentionally additive to keep your source authoritative and generation predictable. Frameworks generate a sibling/subclass (e.g. AutoValue_Foo extends Foo, FooMapperImpl) instead of editing your class.
- How does Lombok differ from a normal annotation processor?Lombok registers as a processor but reaches into javac's internal AST APIs to mutate existing classes (add getters/setters inline). That is unsupported, compiler-version-fragile, and not standard APT, which can only emit new files.
saying these in an interview costs you the question
- Claiming a standard processor can modify or add methods to an existing class (only Lombok hacks do that, via internal APIs)
- Confusing APT with runtime reflection on annotations
- Thinking generated files are NOT re-processed
- Saying APT runs at runtime