为什么 Java 11 运行时忽略了包含 sun.misc 类的 jar?

2022-09-03 15:11:10

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

如果我控制了代码,我会使用java.util.BASE64类,但正如我所说,这些类是从另一个库传入的传递依赖项,我无法更改它。

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

enter image description here

<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]

答案 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)

首先,创建将覆盖 的项目。让我们称之为.在“使用类创建包”下。BASE64Encodersun-misc-overridesrc\main\javasun.miscBASE64Encoder

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

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

使用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>

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

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

<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修复,并且在POM中工作正常。sun-misc-override

现在我的“主”项目被调用,并且有一个类: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进行” - 在类加载器中硬编码。这些执法措施(或类似措施)似乎很可能仍然有效。

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


推荐