编译时注解处理器
编写 AbstractProcessor,在编译时生成源文件或验证代码
编译时注解处理器 是 CoddyKit 上的免费 Java Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Java Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Java Academy 课程共包含 4 节课。
什么是注解处理器
注解处理器(APT,即注解处理工具)会在编译期间运行。它们检查源代码中的注解,并可以生成新的源文件、资源文件,或引发编译器错误和警告。
AbstractProcessor:基类
扩展 javax.annotation.processing.AbstractProcessor。重写 process() 以处理带注解的元素。声明支持的注解和 Java 源版本。
import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.*;
@SupportedAnnotationTypes("com.example.GenerateBuilder")
@SupportedSourceVersion(SourceVersion.RELEASE_17)
public class BuilderProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
for (Element e : roundEnv.getElementsAnnotatedWith(GenerateBuilder.class)) {
generateBuilder((TypeElement) e);
}
return true;
}
private void generateBuilder(TypeElement cls) { /* generate source */ }
}注册处理器
将处理器的完整限定类名注册到 META-INF/services/javax.annotation.processing.Processor 中。构建工具(Maven、Gradle)会自动发现它。
# META-INF/services/javax.annotation.processing.Processor
com.example.BuilderProcessor生成源文件
使用 processingEnv.getFiler().createSourceFile() 写入新的 .java 文件。随后,编译器会在同一轮或下一轮中编译生成的文件。
JavaFileObject file = processingEnv.getFiler()
.createSourceFile("com.example.UserBuilder");
try (Writer w = file.openWriter()) {
w.write("package com.example;\n");
w.write("public class UserBuilder {\n");
w.write(" // generated builder\n");
w.write("}\n");
}检查元素模型
注解处理器处理的是 Element 元素,而不是 Class 类,因为此时源代码尚未编译。请使用 TypeElement、VariableElement 和 ExecutableElement。
TypeElement classElement = (TypeElement) element;
String className = classElement.getSimpleName().toString();
List<VariableElement> fields = classElement.getEnclosedElements().stream()
.filter(e -> e.getKind() == ElementKind.FIELD)
.map(e -> (VariableElement) e)
.collect(Collectors.toList());输出编译器错误
调用 processingEnv.getMessager().printMessage() 输出错误、警告或提示信息。自定义约束注解就是通过这种方式在编译时报告违规情况的。
processingEnv.getMessager().printMessage(
Diagnostic.Kind.ERROR,
"@GenerateBuilder requires at least one field",
element
);多轮处理
注解处理会分轮进行。如果生成的文件包含注解,处理器可能会在下一轮再次运行。roundEnv.processingOver() 表示最后一轮。
if (roundEnv.processingOver()) {
// last round — write summary files or do cleanup
}Lombok 的底层实现
Lombok 使用一种非标准的 APT 扩展来修改现有类的 AST(规范不允许这样做)。它的 @Data、@Builder 和 @Getter 等注解会直接将方法生成到已编译的类中。
MapStruct 代码生成
MapStruct 会在编译时生成类型安全的映射器实现。它读取带有 @Mapper 注解的接口,并将实现写成普通的 Java 类,从而在运行时完全不需要反射。
@Mapper
public interface UserMapper {
UserDto toDto(User user);
User toEntity(UserDto dto);
}
// MapStruct generates: UserMapperImpl.java at compile time测试注解处理器
请使用 google/compile-testing 或 Kapt(用于 Kotlin)对处理器进行单元测试。输入源代码字符串,并断言生成的文件或编译器错误。
JavaFileObject src = JavaFileObjects.forSourceString("Test",
"@GenerateBuilder public class Test { private String name; }");
Compilation c = Compiler.javac().withProcessors(new BuilderProcessor()).compile(src);
CompilationSubject.assertThat(c).succeeded();
CompilationSubject.assertThat(c).generatedSourceFile("TestBuilder");处理器打包
将处理器打包到单独的 Maven 模块中。注解模块(仅包含注解)是一个 compile 依赖;处理器模块使用 annotationProcessor 作用域,绝不能作为运行时依赖。
// build.gradle:
dependencies {
implementation "com.example:my-annotations:1.0"
annotationProcessor "com.example:my-processor:1.0"
}快速检查
在哪里注册注解处理器,才能实现自动发现?
回顾
扩展 AbstractProcessor,在 META-INF/services 中注册处理器,使用 Filer 生成源代码,并使用 Messager 输出错误。将处理器单独打包。使用 compile-testing 进行单元测试,从而消除运行时的反射开销。
常见问题解答
「编译时注解处理器」课时是免费的吗?
是的 — 「编译时注解处理器」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Java Academy 课程的其余内容,请升级到 CoddyKit PRO。 Java Academy 课程共包含 4 节课。
「编译时注解处理器」这节课中我会学到什么?
编写 AbstractProcessor,在编译时生成源文件或验证代码 你通过在浏览器中直接运行的动手代码来练习 Java Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Java Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Java Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「编译时注解处理器」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Java Academy 课中编写并运行代码吗?
能。每节 Java Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 定义注解:元素与默认值
- 保留策略与目标类型
- 运行时注解处理
- 编译时注解处理器