class lombok.javac.apt.LombokProcessor (in unnamed module @0x43a188b6) cannot access class com.sun.t
'# class lombok.javac.apt.LombokProcessor (in unnamed module @0x43a188b6) cannot access class com.sun.t
一、背景与问题
在使用 Lombok 时,开发者可能会遇到如下错误:
class lombok.javac.apt.LombokProcessor (in unnamed module @0x43a188b6) cannot access class com.sun.tools.javac.processing.JavacProcessingExtension (in module java.compiler)或更具体的错误:
class lombok.javac.apt.LombokProcessor (in unnamed module @0x43a188b6) cannot access class com.sun.t...这个错误通常发生在 JDK 9+ 环境中,尤其是使用模块化系统(Jigsaw)后。其根本原因是 Lombok 依赖的某些内部类(如 com.sun.tools.javac.processing.JavacProcessingExtension)在模块化后被标记为 module-info.java 的内部API,外部代码无法直接访问。
二、基本原理
1. Lombok 的工作原理
Lombok 是通过 Java Annotation Processing Tool (APT) 实现的。其核心是 LombokProcessor 类,它在编译阶段处理注解(如 @Data、@Getter 等),并生成对应的 getter/setter 方法。
核心流程:
- 编译器发现注解(如
@Data)时,会调用LombokProcessor。 LombokProcessor通过ProcessingEnvironment获取上下文信息。- 生成对应的 Java 代码(如
toString()方法)并注入到源码中。
2. JDK 模块化的影响
JDK 9 引入了模块系统(module-info.java),所有内部API默认不可访问。例如:
// 原生 JDK 8 的行为(可访问)
com.sun.tools.javac.processing.JavacProcessingExtension
// JDK 9+ 的行为(模块化后不可访问)
com.sun.tools.javac.processing.JavacProcessingExtensionLombok 在 JDK 8 中直接依赖这些内部类,但在 JDK 9+ 中需要通过 --add-opens 参数显式开放模块。
三、环境准备
1. JDK 版本要求
- 推荐 JDK 版本:JDK 8(避免模块化问题)
- 兼容 JDK 版本:JDK 9+(需特殊配置)
2. 依赖配置(Maven 示例)
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>四、核心实现
1. 错误场景示例
代码示例 1:使用 @Data 注解的 POJO
@Data
public class User {
private String name;
private int age;
}错误日志:
class lombok.javac.apt.LombokProcessor (in unnamed module @0x43a188b6) cannot access class com.sun.tools.javac.processing.JavacProcessingExtension (in module java.compiler)2. 错误原因分析
- Lombok 的
LombokProcessor依赖com.sun.tools.javac.processing.JavacProcessingExtension。 - JDK 9+ 中,
java.compiler模块默认不允许外部访问其内部类。 - 因此,
LombokProcessor无法访问JavacProcessingExtension,导致编译失败。
3. 解决方案
方案一:降级 JDK 到 8.x
# 设置 JDK 版本
export JAVA_HOME=/path/to/jdk8方案二:在 JDK 9+ 中配置 --add-opens
Maven 配置:
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<maven.compiler.compilerArgs>
--add-opens=java.compiler/java.lang.invoke
--add-opens=java.compiler/java.util
</maven.compiler.compilerArgs>
</properties>Gradle 配置:
tasks.withType(JavaCompile) {
options.compilerArgs += [
'--add-opens=java.compiler/java.lang.invoke',
'--add-opens=java.compiler/java.util'
]
}五、完整案例
1. 案例:Spring Boot + Lombok 项目
项目结构:
src/
├── main/
│ └── java/
│ └── com.example.demo/
│ └── User.java
└── test/
└── com.example.demo/
└── UserTest.java代码示例 2:User.java
package com.example.demo;
import lombok.Data;
@Data
public class User {
private String name;
private int age;
}代码示例 3:UserTest.java
package com.example.demo;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class UserTest {
@Test
public void testUser() {
User user = new User();
user.setName("Alice");
user.setAge(30);
assertEquals("Alice", user.getName());
assertEquals(30, user.getAge());
}
}Maven 配置(JDK 11+):
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<maven.compiler.compilerArgs>
--add-opens=java.compiler/java.lang.invoke
--add-opens=java.compiler/java.util
</maven.compiler.compilerArgs>
</properties>运行结果:
- 如果配置正确,测试通过。
- 如果未配置
--add-opens,编译失败。
六、源码解析
1. LombokProcessor 源码片段
public class LombokProcessor extends AbstractProcessor {
private final JavacProcessingExtension javacProcessingExtension;
public LombokProcessor() {
this.javacProcessingExtension = (JavacProcessingExtension) ProcessingEnvironment
.getEnvironment().getMessager().getProcessingEnvironment()
.getOptions().get("lombok");
}
// ... 其他代码
}关键点:
JavacProcessingExtension是 JDK 内部类,模块化后不可访问。- 需要通过
--add-opens显式开放模块。
2. 编译器处理流程
- 编译器检测注解(如
@Data)。 - 调用
LombokProcessor。 LombokProcessor生成代码并注入到源码中。- 编译器继续处理生成的代码。
七、进阶使用
1. 自定义注解处理器
代码示例 4:自定义注解 @Log
@Retention(RUNTIME)
@Target(ElementType.METHOD)
public @interface Log {
}代码示例 5:自定义注解处理器
@SupportedAnnotationTypes("com.example.Log")
public class LogProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
for (TypeElement annotation : annotations) {
for (Element element : roundEnv.getElementsAnnotatedWith(annotation)) {
// 生成日志代码
String className = element.getEnclosingElement().getSimpleName().toString();
String methodName = element.getSimpleName().toString();
String code = String.format(
"System.out.println(\"Calling %s.%s\");", className, methodName
);
// 注入代码到源码中
// ...
}
}
return true;
}
}注意事项:
- 需要配置
@SupportedAnnotationTypes。 - 需要处理多轮编译(
RoundEnvironment)。
八、性能与工程实践
1. 性能优化
- 避免过度使用注解:
@Data会生成大量代码,可能导致编译变慢。 - 使用
@SneakyThrows代替try-catch:减少冗余代码。 - 配置
lombok.config:禁用不需要的注解。
# lombok.config 示例
lombok.addLombokGeneratedAnnotation=false
lombok.altStringConstructor=false2. 安全风险
- 内部API依赖:Lombok 依赖 JDK 内部API,可能存在兼容性风险。
- 代码注入风险:Lombok 生成的代码可能引入潜在安全漏洞(如未校验输入)。
九、常见问题与踩坑
1. 常见错误
| 错误类型 | 原因 | 解决方法 |
|---|---|---|
| 编译失败 | JDK 模块化问题 | 使用 JDK 8 或配置 --add-opens |
| 代码注入失败 | 未正确配置注解处理器 | 检查 @SupportedAnnotationTypes |
| 性能下降 | 过多使用 @Data | 替换为部分注解(如 @Getter) |
2. 典型错误示例
错误代码:
@Data
public class User {
private String name;
}错误原因:
- JDK 9+ 编译器无法访问
JavacProcessingExtension。
修复代码:
<properties>
<maven.compiler.compilerArgs>
--add-opens=java.compiler/java.lang.invoke
</maven.compiler.compilerArgs>
</properties>十、最佳实践
1. 推荐场景
- 快速开发:减少样板代码,提高开发效率。
- 团队协作:统一代码风格,避免手动编写 getter/setter。
- 简单项目:不需要深度控制生成代码的场景。
2. 不推荐场景
- 需要完全控制代码:如安全敏感的系统(如金融、医疗)。
- 遗留系统升级:可能引入兼容性问题。
- JDK 9+ 环境:需额外配置,可能增加维护成本。
十一、总结
Lombok 的 LombokProcessor 在 JDK 9+ 环境中可能因模块化问题导致编译失败。其根本原因是依赖 JDK 内部API,而 JDK 模块化后这些API默认不可访问。开发者应根据实际情况选择解决方案:降级 JDK 或配置 --add-opens。
在实际项目中,Lombok 能显著提升开发效率,但需注意其局限性。对于安全敏感或需要深度控制的场景,建议谨慎使用或结合手动代码。合理配置和性能优化是使用 Lombok 的关键,同时需关注 JDK 版本兼容性带来的潜在风险。
评论已关闭