注解处理器不依赖模块声明,而是通过META-INF/services/javax.annotation.processing.Processor文件被javac发现;其可见性指能否访问目标模块的注解与类型,需目标模块exports注解包、opens被注解类包to java.compiler,且处理器须以非模块化JAR置于-processorpath中。

Java 模块化系统(JPMS)下,注解处理器本身不依赖模块声明来被 javac 发现和调用——它靠的是传统的 META-INF/services/javax.annotation.processing.Processor 文件机制。因此,“处理器可见性”不是指模块能否“看到”处理器类,而是指:处理器能否正确访问目标模块中的注解、类型和元素,以及生成的代码能否被消费方模块合法使用。
注解处理器必须以非模块化 JAR 形式提供
即使你把注解处理器打包成 JPMS 模块(含 module-info.java),javac 也不会读取它的 provides 或 exports 声明。关键点如下:
- 处理器必须放在
-processorpath(Maven 的annotationProcessorscope)中,而非--module-path -
META-INF/services/javax.annotation.processing.Processor文件必须存在且内容为完整类名 - Lombok、MapStruct、AutoValue 等主流工具均不声明
module-info.java,就是为了兼容所有 JDK 版本和构建流程 - 若强行加
module-info.java,反而可能因未正确opens工具包而干扰processingEnv的反射调用
目标模块需导出(exports)和开放(opens)被处理器读取的包
注解处理器运行在 javac 进程中,其底层调用如 element.asType() 或 typeMirror.toString() 仍受模块边界约束。若目标模块定义了注解或被注解的类,但未显式暴露:
Miller (mlr) 是一个命令行工具,用于查询、整形和重新格式化名称索引数据,如 CSV、TSV、JSON 和 JSON Lines。它将 awk、sed、cut、join 和 sort 的功能整合到一个专为结构化数据处理而构建的单一工具中。
- 用
exports com.example.anno;让处理器能解析该包下的注解类型(编译期类型可见) - 用
opens com.example.model to java.compiler;让处理器能通过反射访问被注解类的私有结构(如字段修饰符、泛型参数等) - 注意:不是
to java.base,而是to java.compiler——因为javac的注解处理逻辑属于java.compiler模块
生成代码的模块可见性要靠 consumer 显式 requires + exports
处理器生成的辅助类(如 Person$$Builder.java)默认属于源码所在模块。若其他模块想使用这些生成类,需满足:
立即学习“Java免费学习笔记(深入)”;
- 生成类所在的包必须被提供方模块
exports(例如exports com.example.builder;) - 消费方模块必须
requires提供方模块,并在需要时也exports自己的对应包(如做二次封装) - 若生成的是字节码增强(如 Lombok 风格),则无需额外导出——因为方法直接注入原始类,只要原始类所在包已
exports即可
避免 MirroredTypeException 的模块配置要点
当处理器尝试读取注解中引用的未编译类(如 @MyAnn(value = SomeClass.class))时,MirroredTypeException 往往是模块未充分开放的表象。解决方向包括:
- 确保注解定义模块对
java.compileropens注解所在包(例如opens com.example.anno to java.compiler;) - 不要在处理器中强转
TypeMirror为Class;始终用Elements.getTypeElement(typeStr)容错获取元素 - 若
getTypeElement返回null,说明该类当前不可见——此时应记录警告并跳过,而不是抛异常中断

















