JDK21自定义注解处理器无法访问jdk.compiler模块问题排查
问题场景
参考Lombok实现逻辑,在JDK21中通过注解处理器初始化阶段调用implAddOpens方法,尝试打开jdk.compiler模块的相关包。但将自定义注解处理器用maven clean install打包后,在其他项目中使用时出现编译错误:
org.example.async.log.client.annotation.AsyncLogProcessor(位于未命名模块)无法访问com.sun.tools.javac.api.JavacTrees(位于jdk.compiler模块),原因是jdk.compiler未向未命名模块导出该包。
调试发现getOwnModule返回未命名模块,而JDK源码中implAddOpens对未命名模块直接返回,不执行打开操作。尽管注解处理器项目已添加module-info.java声明模块依赖,问题仍未解决。
此前尝试的两种方案均无效:
- 移除
annotationProcessorPaths中的自定义处理器:导致自定义注解处理器完全不生效 - 移除注解处理器的
module-info.java,改用JVM参数--add-opens打开相关包并添加<fork>true</fork>:仍出现访问错误,且保留Lombok时自定义处理器会被跳过
正确解决方案步骤
1. 确保注解处理器项目为模块化结构(保留module-info.java)
在注解处理器的module-info.java中,明确声明对jdk.compiler的依赖,并通过provides语句暴露处理器实现:
module org.example.async.log.client.annotation { requires jdk.compiler; requires lombok; // 若依赖Lombok则添加 exports org.example.async.log.client.annotation; provides javax.annotation.processing.Processor with org.example.async.log.client.annotation.AsyncLogProcessor; }
核心是provides语句,确保编译器能识别到模块化的注解处理器,避免处理器落入未命名模块。
2. 在使用方项目中正确配置Maven编译器插件
必须将自定义处理器作为模块化依赖加入annotationProcessorPaths,同时给指定模块添加--add-opens权限,而非未命名模块:
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.11.0</version> <configuration> <release>21</release> <fork>true</fork> <annotationProcessorPaths> <path> <groupId>org.example</groupId> <artifactId>async-log-client-annotation</artifactId> <version>1.0.0</version> </path> <path> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.30</version> </path> </annotationProcessorPaths> <compilerArgs> <!-- 给自定义处理器模块打开jdk.compiler的内部包权限 --> <arg>--add-opens=jdk.compiler/com.sun.tools.javac.api=org.example.async.log.client.annotation</arg> <arg>--add-opens=jdk.compiler/com.sun.tools.javac.processing=org.example.async.log.client.annotation</arg> <!-- 按需添加其他需要打开的包 --> <!-- 强制Lombok包含自定义处理器 --> <arg>-Alombok.processors.include=org.example.async.log.client.annotation.AsyncLogProcessor</arg> </compilerArgs> </configuration> </plugin> </plugins> </build>
这里的关键是--add-opens参数要指定自定义处理器的模块名,JDK会允许给明确的模块打开内部包权限,而非未命名模块。
3. 验证打包后的模块化JAR
执行jar tf target/async-log-client-annotation-1.0.0.jar,确认根目录下存在module-info.class,确保处理器JAR是模块化的。
原方案失败原因
- 方案1移除
annotationProcessorPaths:编译器无法定位自定义处理器,直接导致失效 - 方案2移除
module-info.java:处理器回到未命名模块,JDK的implAddOpens不对未命名模块执行打开操作;同时--add-opens给未命名模块开权限在JDK21中限制更严格,加上Lombok的处理器优先级逻辑,导致自定义处理器被跳过
内容的提问来源于stack exchange,提问作者Photon

