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 方法。

核心流程:

  1. 编译器发现注解(如 @Data)时,会调用 LombokProcessor。
  2. LombokProcessor 通过 ProcessingEnvironment 获取上下文信息。
  3. 生成对应的 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.JavacProcessingExtension

Lombok 在 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. 编译器处理流程

  1. 编译器检测注解(如 @Data)。
  2. 调用 LombokProcessor。
  3. LombokProcessor 生成代码并注入到源码中。
  4. 编译器继续处理生成的代码。

七、进阶使用

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=false

2. 安全风险

  • 内部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 版本兼容性带来的潜在风险。

评论已关闭

推荐阅读

AIGC实战——Transformer模型
2024年12月01日
Socket TCP 和 UDP 编程基础(Python)
2024年11月30日
python , tcp , udp
如何使用 ChatGPT 进行学术润色?你需要这些指令
2024年12月01日
AI
最新 Python 调用 OpenAi 详细教程实现问答、图像合成、图像理解、语音合成、语音识别(详细教程)
2024年11月24日
ChatGPT 和 DALL·E 2 配合生成故事绘本
2024年12月01日
omegaconf,一个超强的 Python 库!
2024年11月24日
【视觉AIGC识别】误差特征、人脸伪造检测、其他类型假图检测
2024年12月01日
[超级详细]如何在深度学习训练模型过程中使用 GPU 加速
2024年11月29日
Python 物理引擎pymunk最完整教程
2024年11月27日
MediaPipe 人体姿态与手指关键点检测教程
2024年11月27日
深入了解 Taipy:Python 打造 Web 应用的全面教程
2024年11月26日
基于Transformer的时间序列预测模型
2024年11月25日
Python在金融大数据分析中的AI应用(股价分析、量化交易)实战
2024年11月25日
AIGC Gradio系列学习教程之Components
2024年12月01日
Python3 `asyncio` — 异步 I/O,事件循环和并发工具
2024年11月30日
llama-factory SFT系列教程:大模型在自定义数据集 LoRA 训练与部署
2024年12月01日
Python 多线程和多进程用法
2024年11月24日
Python socket详解,全网最全教程
2024年11月27日
python之plot()和subplot()画图
2024年11月26日
理解 DALL·E 2、Stable Diffusion 和 Midjourney 工作原理
2024年12月01日