java apt在编译期生成源码,需实现processor接口、用source保留策略定义注解、继承abstractprocessor重写process方法,通过filer写入文件,并在meta-inf/services或maven中注册处理器。

Java 中通过 APT(Annotation Processing Tool)在编译期动态生成 Java 源代码,核心是实现 javax.annotation.processing.Processor 接口,并配合 @SupportedAnnotationTypes 和 @SupportedSourceVersion 声明支持的注解与 Java 版本。生成的代码由 Filer 写入源码目录,被后续编译流程自动编译。
定义并注册自定义注解
先创建一个运行时保留的注解,供开发者标记目标类或字段:
@Target({ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.SOURCE) // 必须为 SOURCE,否则注解处理器无法捕获
public @interface GenerateBuilder {
}
注意:注解的 @Retention 必须设为 SOURCE,因为 APT 只处理源码阶段的注解;若用 CLASS 或 RUNTIME,处理器将收不到该注解。
编写注解处理器
继承 AbstractProcessor,重写 process() 方法,在其中解析被注解的元素并生成 Java 文件:
Miller (mlr) 是一个命令行工具,用于查询、整形和重新格式化名称索引数据,如 CSV、TSV、JSON 和 JSON Lines。它将 awk、sed、cut、join 和 sort 的功能整合到一个专为结构化数据处理而构建的单一工具中。
- 通过
RoundEnvironment获取所有带指定注解的Element(如类、字段) - 使用
Elements工具类获取类型名、包名等元信息 - 调用
Filer.createSourceFile()创建新源文件,返回JavaFileObject - 用
Writer向其写入合法 Java 源码(注意缩进、分号、import 等语法)
示例片段:
@Override
public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {
for (Element element : roundEnv.getElementsAnnotatedWith(GenerateBuilder.class)) {
if (element.getKind() == ElementKind.CLASS) {
TypeElement classElement = (TypeElement) element;
String packageName = elements.getPackageOf(classElement).getQualifiedName().toString();
String className = classElement.getSimpleName().toString();
String builderName = className + "Builder";
try (Writer writer = filer.createSourceFile(
packageName + "." + builderName).openWriter()) {
writer.write("package " + packageName + ";\n");
writer.write("public class " + builderName + " { }\n");
} catch (IOException e) {
messager.printMessage(Diagnostic.Kind.ERROR, "生成失败: " + e);
}
}
}
return true;
}
正确配置和启用处理器
确保注解处理器能被编译器识别并执行:
- Maven 项目中,将处理器模块打包为 jar,并在使用方的
pom.xml中用<annotationprocessor></annotationprocessor>或<processor></processor>显式声明(JDK 8+ 推荐前者) - 或在处理器 jar 的
META-INF/services/javax.annotation.processing.Processor文件中写入全限定类名(如com.example.MyProcessor) - IDE(如 IntelliJ)需开启「Enable annotation processing」并在设置中指定输出路径(如
target/generated-sources/annotations)
生成代码时的实用技巧
避免手拼字符串导致语法错误,推荐结合模板或轻量工具:
- 用
String.format()或StringBuilder组织结构清晰的代码块 - 借助
JavaPoet库(Square 出品)安全构建类、方法、字段等,自动处理 import、缩进、泛型等细节 - 通过
Messager输出提示或错误(messager.printMessage(WARNING, "...")),便于调试 - 生成前检查是否已存在同名类(
Filer会抛异常),可加逻辑跳过重复生成
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










