Back to results for “Build Tools: Maven & Gradle”
Java › Annotations

What is the difference between compile-time annotation processing (via javax.annotation.processing.Processor) and runtime reflection-based annotation reading?

Intermediate

Answer

Compile-time annotation processing runs during compilation itself (implementing AbstractProcessor, registered via META-INF/services), generating new source files or validating code structure before the .class files even exist -- used by tools like Lombok (generating getters/setters) or Dagger (generating dependency injection code) -- while runtime reflection reads already-compiled annotation metadata during program execution, incurring reflection's inherent performance overhead but requiring no separate build step, making compile-time processing generally preferred for performance-sensitive, code-generation scenarios.
@SupportedAnnotationTypes("com.example.GenerateBuilder")
@SupportedSourceVersion(SourceVersion.RELEASE_17)
public class BuilderProcessor extends AbstractProcessor {
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        // generates new .java source files at compile time
        return true;
    }
}
Real-world example Lombok's @Data annotation is processed entirely at compile time via an annotation processor, generating getter/setter/equals/hashCode methods directly into the bytecode before the JVM ever runs the program, avoiding any runtime reflection overhead that a similar reflection-based approach would incur on every method call.

Common follow-ups: Why do frameworks like Dagger prefer compile-time code generation over Spring's runtime reflection-based approach?;What are the debugging challenges specific to compile-time generated code?