【问题标题】:Why is the Java 11 runtime ignoring my jar containing sun.misc classes?为什么 Java 11 运行时会忽略包含 sun.misc 类的 jar?
【发布时间】:2026-01-04 19:45:01
【问题描述】:

我正在尝试将我的代码库升级到 Java 11。不幸的是,我的代码依赖于内部使用 sun.misc.BASE64EncoderDecoder 的第三方库。由于 sun.misc 包已从 Java 11 JRE 中删除,因此它失败了。该库的所有者尚未替换该依赖项,因此我坚持了一段时间。

如果我可以控制代码,我会使用 java.util.BASE64 类,但正如我所说,这些是作为来自另一个库的传递依赖项进来的,我无法更改。

我想我会很聪明,用这些类创建一个新的 jar,但由于某种原因,这个 jar 被忽略了。

<dependency>
    <groupId>sun.misc</groupId>
    <artifactId>BASE64</artifactId>
    <version>1.8</version>
    <scope>system</scope>
    <systemPath>${project.basedir}/lib/sun.jar</systemPath>
</dependency>

我也尝试将它显式添加到类路径中,但仍然没有成功

这是 JRE 阻止您使用的那些包之一,还是我缺少某些模块规范,或者这是一个显示停止器?

这是输出

java.lang.NoClassDefFoundError: sun/misc/BASE64Encoder
at com.propsco.util.support.PropsLoader.save(PropsLoader.java:478) ~[props-client-2.2.1.jar:na]

【问题讨论】:

  • 请解释一下“但是由于某种原因,那个 jar 被忽略了。” 您的应用程序是模块化应用程序吗?BASE64Encoder/Decoder 出现什么错误?
  • 你能再具体一点吗?您在日志中看到 NoClassDefFoundError 了吗?您可以将堆栈跟踪附加到问题吗?
  • 是的@ZhekaKozlov,我添加了输出
  • 您是否尝试将其添加到系统库中?现在在“JAVA_HOME/jmods”中。
  • 好吧,这可能与 jdk.unsupported.jmod 模块中的 noew 选项 --patch-modulesee *.com/questions/48148607/… sun/misc 有关。 cli 上的参数可能类似于--patch-module modulename=yourmodule.jmod

标签: java java-11


【解决方案1】:

这个答案是用

写的
> java --version
openjdk 11.0.3 2019-04-16
OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.3+7)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.3+7, mixed mode)

首先,您创建将覆盖BASE64Encoder 的项目。我们称之为sun-misc-override。在src\main\java 下创建带有BASE64Encoder 类的sun.misc 包。

package sun.misc;

public class BASE64Encoder {
    public String encode(byte[] aBuffer) {
        return "Fake it until you make it!";
    }
}

如果你尝试编译它,你会得到一个sun\misc\BASE64Encoder.java:1: error: package exists in another module: jdk.unsupported 错误。

这给了我们一个提示,我们需要patch modulejdk.unsupported。这是因为在 Java 9 中推出模块系统时,原始 sun.misc 包中的类已移至 jdk.unsupported 模块,然后随着时间的推移被移除(请参阅 JEP-260)。

使用 Maven,您可以像这样配置编译器插件:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.1</version>
    <configuration>
        <release>11</release>
        <compilerArgs>
            <arg>--patch-module</arg>
            <arg>jdk.unsupported=${project.basedir}/src/main/java</arg>
        </compilerArgs>
    </configuration>
</plugin>

com.example:sun-misc-override:1.0.0-SNAPSHOT 构建完成后,将生成的 JAR 放入您的“主”项目中 - 就像您所做的那样。在lib 目录中。我还没有找到让它与常规 Maven 依赖项一起工作的方法。

现在,在您的“主”项目中配置编译器插件:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.1</version>
    <configuration>
        <release>11</release>
        <compilerArgs>
            <arg>--patch-module=jdk.unsupported=${project.basedir}/lib/sun-misc-override-1.0.0-SNAPSHOT.jar</arg>
        </compilerArgs>
    </configuration>
</plugin>

(可能是因为MCOMPILER-311我在尝试使用时遇到了NPE

<compilerArgs>
    <arg>--patch-module</arg>
    <arg>jdk.unsupported=${project.basedir}/lib/sun-misc-override-1.0.0-SNAPSHOT.jar</arg>
</compilerArgs>

即使该错误应该使用 maven-compiler-plugin 3.8.0 修复,并且在 sun-misc-override 的 POM 中运行良好。)

现在我的“主”项目被称为j11 并且有一个类:

package com.example;

import sun.misc.BASE64Encoder;

public class BASE64EncoderTest {
    public static void main(String[] args) {
        System.out.println("Testing - " + new BASE64Encoder().encode(new byte[0]));
    }
}

要运行它,您需要再次指定--patch-module

> java --patch-module=jdk.unsupported=lib\sun-misc-override-1.0.0-SNAPSHOT.jar -cp target\j11-1.0.0-SNAPSHOT.jar com.example.BASE64EncoderTest
Testing - Fake it until you make it!

【讨论】:

    【解决方案2】:

    在过去的版本中,Sun 竭尽全力确保无法像您现在尝试的那样篡改运行时(如果它像这样简单,每个人都可以创建自己的运行时私有变体- 你肯定会明白那不是一件好事)。我不知道细节,但他们可能归结为“如果包名称是这样或那样或那样,那么加载只会从 rt.jar 发生” - 硬编码在类加载器的东西中。这些强制措施(或类似措施)似乎很可能仍然有效。

    放弃我的其余答案,因为我认为您非常了解您的选择是什么,而这不是问题所在。

    【讨论】:

    • 在较旧的 Java 版本中,如果您更改引导类路径,您可以替换 rt.jar(我认为标志是 -XX:bootclasspath?)。但我不知道它如何与 Java 9+ 中的新模块系统交互。
    • @Erwin Smout 我怀疑这是问题所在。