Java注解处理器
注解处理器(Annotation Processor)在编译期处理注解,实现代码生成、编译检查等功能。
注解处理器原理
注解处理器是javac的工具,在编译阶段扫描和处理注解。可以生成新的Java文件,但不能修改已有文件。
执行时机
Java
编译开始 → 多轮处理 → 编译结束
↓
处理器扫描注解 → 生成新文件 → 再次扫描新生成的文件
实现注解处理器
1. 定义注解
Java
// 保留策略必须是SOURCE或CLASS(运行时不需要)
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface Builder {
String builderClassName() default "";
}
2. 继承AbstractProcessor
Java
@SupportedAnnotationTypes("com.example.Builder") // 处理的注解
@SupportedSourceVersion(SourceVersion.RELEASE_11) // Java版本
public class BuilderProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
// 处理逻辑
return true; // 返回true表示已处理
}
}
3. 完整处理器实现
Java
@SupportedAnnotationTypes("com.example.Builder")
@SupportedSourceVersion(SourceVersion.RELEASE_11)
public class BuilderProcessor extends AbstractProcessor {
private Filer filer; // 文件操作工具
private Messager messager; // 消息输出工具
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
filer = processingEnv.getFiler();
messager = processingEnv.getMessager();
}
@Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
// 遍历所有被@Builder标注的元素
for (TypeElement annotation : annotations) {
Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(annotation);
for (Element element : elements) {
if (element.getKind() != ElementKind.CLASS) {
error(element, "@Builder只能用于类");
continue;
}
// 处理类
processClass((TypeElement) element);
}
}
return true;
}
private void processClass(TypeElement classElement) {
String className = classElement.getSimpleName().toString();
String packageName = getPackageName(classElement);
String builderClassName = className + "Builder";
// 生成Builder类代码
try {
JavaFileObject file = filer.createSourceFile(
packageName + "." + builderClassName);
try (PrintWriter writer = new PrintWriter(file.openWriter())) {
writer.println("package " + packageName + ";");
writer.println("public class " + builderClassName + " {");
writer.println(" // 生成的代码...");
writer.println("}");
}
} catch (IOException e) {
error(classElement, "生成代码失败: " + e.getMessage());
}
}
private String getPackageName(TypeElement element) {
Element enclosing = element.getEnclosingElement();
while (enclosing.getKind() != ElementKind.PACKAGE) {
enclosing = enclosing.getEnclosingElement();
}
return ((PackageElement) enclosing).getQualifiedName().toString();
}
private void error(Element element, String message) {
messager.printMessage(Diagnostic.Kind.ERROR, message, element);
}
}
注册处理器
方式1:META-INF/services
在 META-INF/services/javax.annotation.processing.Processor 文件中写入:
XML
com.example.BuilderProcessor
com.example.FactoryProcessor
方式2:@AutoService(推荐)
Java
@AutoService(Processor.class)
@SupportedAnnotationTypes("com.example.Builder")
@SupportedSourceVersion(SourceVersion.RELEASE_11)
public class BuilderProcessor extends AbstractProcessor {
// ...
}
需要依赖:
Java
<dependency>
<groupId>com.google.auto.service</groupId>
<artifactId>auto-service</artifactId>
<version>1.1.1</version>
</dependency>
Processor核心API
Java
public abstract class AbstractProcessor implements Processor {
// 初始化,获取处理环境
public synchronized void init(ProcessingEnvironment processingEnv);
// 处理注解(核心方法)
public abstract boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv);
// 支持的注解类型
public Set<String> getSupportedAnnotationTypes();
// 支持的Java版本
public SourceVersion getSupportedSourceVersion();
}
ProcessingEnvironment工具
text
// 文件操作
Filer filer = processingEnv.getFiler();
filer.createSourceFile("com.example.Generated"); // 创建Java文件
filer.createResource(StandardLocation.CLASS_OUTPUT, "", "config.json");
// 消息输出
Messager messager = processingEnv.getMessager();
messager.printMessage(Diagnostic.Kind.ERROR, "错误信息");
messager.printMessage(Diagnostic.Kind.WARNING, "警告信息");
messager.printMessage(Diagnostic.Kind.NOTE, "提示信息");
// 类型工具
Types types = processingEnv.getTypeUtils();
Elements elements = processingEnv.getElementUtils();
// 选项配置
Map<String, String> options = processingEnv.getOptions();
Element体系
text
// 元素类型判断
Element element = ...;
if (element.getKind() == ElementKind.CLASS) {
TypeElement classElement = (TypeElement) element;
}
// 常见Element类型
ElementKind.CLASS // 类
ElementKind.INTERFACE // 接口
ElementKind.FIELD // 字段
ElementKind.METHOD // 方法
ElementKind.PARAMETER // 参数
ElementKind.PACKAGE // 包
注意事项
处理器生成的文件会被编译,并触发新一轮注解处理
不能修改已有源文件,只能生成新文件
使用 Filer 创建文件,不要直接用 File API
错误信息用 Messager 输出,不要用 System.out
要点总结
- 继承 AbstractProcessor 实现 process() 方法
- 用 @SupportedAnnotationTypes 指定处理的注解
- 通过 META-INF/services 或 @AutoService 注册处理器
- 使用 Filer 生成源文件,Messager 输出错误信息
- 只能生成新文件,不能修改已有文件
📝 发现内容有误?点击此处直接编辑