Lombok 对于 jdk.compiler 内部包的访问与 Java-16 不兼容。

88

我只是将我的一个项目从Java-15升级到16(使用最新版本的这里)。在编译使用lombok库的项目时,出现了以下问题:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.16</version>
</dependency>

我有点卡在了堆栈跟踪上

Caused by: java.lang.IllegalAccessError: class lombok.javac.apt.LombokProcessor (in unnamed module @0x4e670245) cannot access class com.sun.tools.javac.processing.JavacProcessingEnvironment (in module jdk.compiler) because module jdk.compiler does not export com.sun.tools.javac.processing to unnamed module @0x4e670245
    at lombok.javac.apt.LombokProcessor.getJavacProcessingEnvironment (LombokProcessor.java:433)
    at lombok.javac.apt.LombokProcessor.init (LombokProcessor.java:92)
    at lombok.core.AnnotationProcessor$JavacDescriptor.want (AnnotationProcessor.java:160)
    at lombok.core.AnnotationProcessor.init (AnnotationProcessor.java:213)
    at lombok.launch.AnnotationProcessorHider$AnnotationProcessor.init (AnnotationProcessor.java:64)
    at com.sun.tools.javac.processing.JavacProcessingEnvironment$ProcessorState.<init> (JavacProcessingEnvironment.java:702)
    at com.sun.tools.javac.processing.JavacProcessingEnvironment$DiscoveredProcessors$ProcessorStateIterator.next (JavacProcessingEnvironment.java:829)

现在,至少我认为我知道一个方法来解决这个问题,但是即使尝试以下配置在maven-compiler-plugin上,仍然无法解决。

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.1</version>
    <configuration>
        <source>16</source>
        <target>16</target>
        <!--                    <release>16</release>-->
        <compilerArgs>
            <arg>--enable-preview</arg>
            <arg>-Xlint:all</arg>
            <arg>--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED</arg>
        </compilerArgs>
        <!--for unmappable characters in classes-->
        <encoding>UTF-8</encoding>
        <showDeprecation>true</showDeprecation>
        <showWarnings>true</showWarnings>
        <!--for lombok annotations to resolve-->
        <!--contradictory to maven, intelliJ fails with this-->
        <annotationProcessorPaths>
            <path>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.16</version>
            </path>
        </annotationProcessorPaths>
    </configuration>
</plugin>

有人能解决或摆脱这个问题吗?

编辑: 评论中Jorn提供的链接确实与GitHub上的同一问题有关,但是所提出的解决方案仍然不起作用。因此我也添加了以下参数:

<arg>--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED</arg>
<arg>--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED</arg>
<arg>--add-opens=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED</arg>
<arg>--add-opens=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED</arg>
<arg>--add-opens=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED</arg>
<arg>--add-opens=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED</arg>
<arg>--add-opens=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED</arg>
<arg>--add-opens=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED</arg>
<arg>--add-opens=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED</arg>

2
看起来这个问题也有一个开放的问题:https://github.com/rzwitserloot/lombok/issues/2681 似乎需要不止一个add-opens。 - Jorn Vernee
2
查看Maven的-X输出,发现在运行注解处理器时,它没有将所需的标志添加到命令行中。(请注意,您还需要在标志前面加上-J,以便将其传递给javac进程本身)。如果我手动将缺失的-J--add-opens添加到Maven的命令中,则可以正常工作。 - Jorn Vernee
3
既然这个问题现在已经关闭,我会在这里发布我的答案:在编译器插件配置中添加<fork>true</fork>并添加一个缺少的 -J--add-opens=jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED 后,我成功让它运行。 - Jorn Vernee
4
我认为不包含确切错误信息的日志是使用fork=true时的结果。当我手动运行javac时,我看到了更清晰的异常信息。Maven文档提示需要使用fork=true:https://maven.apache.org/plugins/maven-compiler-plugin/compile-mojo.html#compilerArgs "<compilerArgs>如果fork设置为true,则设置要传递给编译器的参数"。如果问题重新开放,我也会在这里发布我使用的配置。 - Jorn Vernee
1
@JornVernee的问题已重新开放。 - Fenio
显示剩余4条评论
12个回答

105

更新::

Lombok v1.18.20 out of the box 支持 JDK 16。.

在同一线程中,其中一个维护者还写道

我们有一些不太熟知的漏洞可以用来弥合一些差距。我们将同时开始处理 gradle 和 maven 插件,这将是一个长期的解决方案。


原始内容::

您在最新的JDK-16版本中看到的异常是由于JEP 396: Strongly Encapsulate JDK Internals by Default(默认情况下强制封装JDK内部)。Lombok正在使用反射访问内部JDK API,在之前的Java版本中,这会导致警告消息,但现在会导致硬错误。

通常情况下,可以通过在运行java时传递--add-opens=<module>/<package>=<accessing module>指令来显式打开内部JDK包,以进行反射。在这种情况下,这些指令需要传递给调用javac时运行的java进程。可以通过在传递给javac的选项前加上-J来完成此操作,这将使其传递给底层JVM。

使用Maven,我能够使用以下编译器插件配置使其工作:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.1</version>
    <configuration>
        <source>16</source>
        <target>16</target>
        <!--                    <release>16</release>-->
        <fork>true</fork>
        <compilerArgs>
            <arg>--enable-preview</arg>
            <arg>-Xlint:all</arg>
            <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED</arg>
            <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED</arg>
            <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED</arg>
            <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED</arg>
            <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED</arg>
            <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED</arg>
            <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED</arg>
            <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED</arg>
            <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED</arg>
            <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED</arg>
        </compilerArgs>
        <!--for unmappable characters in classes-->
        <encoding>UTF-8</encoding>
        <showDeprecation>true</showDeprecation>
        <showWarnings>true</showWarnings>
        <!--for lombok annotations to resolve-->
        <!--contradictory to maven, intelliJ fails with this-->
        <annotationProcessorPaths>
            <path>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.16</version>
            </path>
        </annotationProcessorPaths>
    </configuration>
</plugin>

需要的选项是通过配置中的<compilerArgs>元素传递。

请注意,我在选项前面添加了-J,以便将它们传递给运行javac的JVM,而不是javac选项。

除了问题中列出的--add-opens指令外,还有一个额外的:

-J--add-opens=jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED
<fork>true</fork> 也是必需的,否则根据mvn clean install -X的输出,将会忽略-J选项。查看Maven文档,似乎无论何时使用<compilerArgs>,都需要将fork设置为true

https://maven.apache.org/plugins/maven-compiler-plugin/compile-mojo.html#compilerArgs

<compilerArgs>如果将fork设置为true,则设置要传递给编译器的参数。


1
很快会添加赏金。但也许需要引导一下Lombok应该如何朝着永久解决方案前进。 - Naman
1
向我的团队中的每个人解释为什么要将这么多东西添加到Maven配置文件中以使Lombok正常工作,可能会相当复杂。有一些“记录”(record)使得Lombok变得有些过时,唯一我会想念的是我经常使用的@Accessor(chain=true) - Eugene
1
@Eugene没错,你现在的状态还是比较好的。想象一下,在执行迁移的概念证明时,你告诉人们,他们的BOM依赖项与升级不兼容!更重要的是,处理那些随意使用库进行任何随机注释而甚至不关心其“必要性”的人所产生的噪音。然后向架构师推销这一切又是另一种挣扎。我认为帮助我清理了很多代码的是@RequiredArgsConstructor(onConstructor = @__(@Inject))。手指交叉,但还没有尝试在Java-16上进行注入。 - Naman
35
有趣的是,它总是以相同的方式不断升级。JDK发出一个警告 →“但它仍然可以工作”,几年后:JDK产生错误 →“但我可以用一个选项让它工作”,再过几年,黑客完全停止了工作 →“为什么他们突然破坏了兼容性?” - Holger
3
是的,我们绝对已经因为非法访问警告而感到疲劳。我指责双方——库作者继续使用它,OpenJDK没有寻找人们需要它的原因。我仍然不知道 java.io.Console.cs 的替代品。但同样的事情被暴露为共享机密——因为 OpenJDK 的某些其他部分依赖它。 - Johannes Kuhn
2
值得一提的是,JDK 17 中添加了 Console::charset() 方法:https://github.com/openjdk/jdk/pull/3419 - Jorn Vernee

36

我把lombok版本升级到1.18.20,这样问题就解决了。所以,如果你能升级lombok的话,我建议你这么做。

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.20</version>
</dependency>

现有并已被接受的答案已经提到了这一点。所以不确定为什么这应该是一个单独的答案。 - Naman
3
@Naman,看到这个答案后更容易理解,直截了当。 - aswzen
我也遇到了同样的错误。将lombok升级到最新版本并与Java 17一起使用是有效的。 - Sankalp
Java 8出现了相同的错误:java-1.8.0-openjdk-1.8.0.382 - undefined

19

如果您使用的是Java 11或者任何不同于最新版本的Java版本,请注意IntelliJ可以使用其自己的Maven版本,并挂钩JDK 16/17,因此在从IntelliJ终端执行mvn clean install时可能会出现上述错误。

要检查实际使用的JDK,请在终端中键入mvn --version,你可能会像我一样感到惊讶(我甚至不知道我有JDK 17):

Maven home: /usr/local/Cellar/maven/3.8.4/libexec
Java version: 17.0.1, vendor: Homebrew, runtime: /usr/local/Cellar/openjdk/17.0.1_1/libexec/openjdk.jdk/Contents/Home
Default locale: en_BG, platform encoding: UTF-8
OS name: "mac os x", version: "11.3.1", arch: "x86_64", family: "mac"

同时,当我检查 java --version 时,获得了Java 11。

这里的解决方案是通过Maven选项卡中的Maven目标按钮执行mvn clean install

enter image description here

它正确地使用了JDK 11,也可以通过mvn --version进行验证。


在从Maven目标按钮运行后,我仍然得到相同的错误! - Shailesh Kumar
谢谢你帮了我,节省了很多时间。 - undefined

6

帮助可能遇到此问题的Gradle用户。

对于使用Gradle的用户来说,要正确配置Lombok,请在build.gradle文件中使用compileOnlyannotationProcessor

// Lombok
compileOnly 'org.projectlombok:lombok:1.18.20'
annotationProcessor 'org.projectlombok:lombok:1.18.20'

如果您在使用Lombok,则对于测试依赖项同样适用:
testCompileOnly 'org.projectlombok:lombok:1.18.20'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.20'

另外,如果您想明确生成针对JDK 16的字节码,请使用:

sourceCompatibility = '16'
targetCompatibility = '16'

来源:
设置Lombok和Gradle
Gradle的sourceCompatibility和targetCompatibility


2
如果您正在寻找与JDK 17兼容的版本,请选择1.18.22。 - Rangana Udara

5

如果您在macOS上使用jenv,出现这个问题的原因是环境变量JAVA_HOME没有激活。只需执行以下操作:

jenv enable-plugin export

然后重新打开终端会话,输入命令echo $JAVA_HOME


1

如果以上方法都不起作用

对我来说,问题是由于Maven使用的Java版本。 在安装Maven时,它会自动安装与其兼容的JDK版本并默认使用它。 可以通过mvn -version命令进行检查。

Apache Maven 3.8.6 (someGUID)
Maven home: /opt/homebrew/Cellar/maven/3.8.6/libexec
Java version: 18.0.2.1, vendor: Homebrew, runtime: /opt/homebrew/Cellar/openjdk/18.0.2.1/libexec/openjdk.jdk/Contents/Home
Default locale: en_IN, platform encoding: UTF-8
OS name: "mac os x", version: "12.5.1", arch: "aarch64", family: "mac"

但是机器上的Java版本和项目使用的版本可能不同,例如:

java -version
java version "11.0.16.1" 2022-08-18 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.16.1+1-LTS-1)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.16.1+1-LTS-1, mixed mode)

所以问题出在Maven的Java版本上;可以通过运行以下命令来解决:

`export JAVA_HOME=~{pathToLibrary}/Library/Java/JavaVirtualMachines/jdk-11.0.16.1.jdk/Contents/Home/`

这将更改Maven使用的Java版本,可以通过相同的方式进行验证

`mvn -version
Apache Maven 3.8.6 (someGUID)
Maven home: /opt/homebrew/Cellar/maven/3.8.6/libexec
Java version: 11.0.16.1, vendor: Oracle Corporation, runtime: /Library/Java/JavaVirtualMachines/jdk-11.0.16.1.jdk/Contents/Home
Default locale: en_IN, platform encoding: UTF-8
OS name: "mac os x", version: "12.5.1", arch: "aarch64", family: "mac"`

希望这能有所帮助。

1

作为Petar Bivolarski,我发现maven的JDK版本引用了JDK 18,而我的应用程序应该在JDK 11上运行,因此我已经在我的计算机上更改了JAVA_HOME以引用正确版本的JDK,这将解决我的maven构建问题。


1

您需要更改您的SDK版本。

如果您使用IntelliJ IDEA,可以通过选择“项目”选项卡并在左侧选择“项目”选项来更改SDK版本。项目SDK应为1.8或您在项目中使用的任何版本。Java版本16.0.1不支持访问此版本的lombok。


1

这解决了我在Windows和Intellij上的问题。我的项目使用了java 1.8,但是我的Maven默认使用java 17,因为我机器上同时安装了Java 1.8和17。我通过简单地将set JAVA_HOME=C:\Program Files\Java\jdk1.8.0_211\jre添加到我的mvn.bat文件中来更新Maven的Java版本,你可以在Maven软件所在的位置找到该文件。

要验证,请运行mvn --version,它应该显示Java版本1.8的响应。


0
在IntelliJ中:
步骤1:右键单击您的项目->打开模块设置
步骤2:在“依赖项”选项卡中,设置所有项目JDK与您拥有的JDK匹配。
步骤3:单击应用按钮。 输入图像描述 输入图像描述

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接