修补 java.base 结果 java.lang.LinkageError
Patching java.base results in java.lang.LinkageError
我正在尝试在 Java 11 中做同样的事情,这可以在 java 9 之前用 -Xbootclasspath/p:path
完成。
作为一个简单的示例,我修改了 java.lang.Integer
的 valueOf
方法之一,并使用以下代码编译了项目:
javac --module-source-path=src/java.base --patch-module java.base=src/java.base -d mods $(find src -name '*.java')
然后我 运行 一个简单的示例使用:
java --patch-module java.base=<pathToMyModifiedJavaBaseClasses> -p lib -m my.moduleA/my.moduleA.Main
这很有效,我看到了显示的修改(我从 valueOf
中打印出来的简单内容)。
然而,当我尝试用 java.lang.ClassLoader
做同样的事情时,我在执行程序(编译工作)时收到以下错误:
Error occurred during initialization of boot layer
java.lang.LinkageError: loader 'bootstrap' attempted duplicate class definition for java.lang.invoke.SimpleMethodHandle.
我什至不需要在 java.lang.ClassLoader
中进行更改。我的补丁文件夹中 class 的绝对存在似乎引发了这个错误。 (我只想在 class 的底部添加一个字段)
注意:我只是认为它在 ClassLoader
class 是用 Eclipse 编译时有效。我知道的少数差异之一是 Eclipse 编译器似乎还没有遵循 JEP 280。但是 javac
产生的字节码中也有 invokedynamic
指令,所以我怀疑这是问题所在。
你已经指出了正确的方向。当您使用当前版本的 Eclipse 编译 class 时,它会起作用,因为该编译器尚未遵循 JEP 280,因此它不会使用 invokedynamic
进行字符串连接。
这并不意味着在 ClassLoader
中使用 invokedynamic
通常是有问题的。它仅在 java.lang.invoke
程序包引导期间执行的某些关键代码路径中存在问题,显然,此 class 确实在此代码路径上使用了字符串连接。
在 javac
的情况下,您可以通过选项
强制使用旧的字符串连接代码
-XDstringConcat=inline
。查看 JDK 附带的 ClassLoader.class
的字节码,似乎此 class 已使用此选项编译。事实上,查看一些示例,似乎整个 java.base
模块都是使用该选项编译的,与例如相反。 java.desktop
,其 classes 使用 invokedynamic
进行字符串连接。
所以结论是,要在java.base
模块(在OpenJDK和衍生产品中)中修补classes,使用时使用-XDstringConcat=inline
选项编译它们javac
.
我正在尝试在 Java 11 中做同样的事情,这可以在 java 9 之前用 -Xbootclasspath/p:path
完成。
作为一个简单的示例,我修改了 java.lang.Integer
的 valueOf
方法之一,并使用以下代码编译了项目:
javac --module-source-path=src/java.base --patch-module java.base=src/java.base -d mods $(find src -name '*.java')
然后我 运行 一个简单的示例使用:
java --patch-module java.base=<pathToMyModifiedJavaBaseClasses> -p lib -m my.moduleA/my.moduleA.Main
这很有效,我看到了显示的修改(我从 valueOf
中打印出来的简单内容)。
然而,当我尝试用 java.lang.ClassLoader
做同样的事情时,我在执行程序(编译工作)时收到以下错误:
Error occurred during initialization of boot layer
java.lang.LinkageError: loader 'bootstrap' attempted duplicate class definition for java.lang.invoke.SimpleMethodHandle.
我什至不需要在 java.lang.ClassLoader
中进行更改。我的补丁文件夹中 class 的绝对存在似乎引发了这个错误。 (我只想在 class 的底部添加一个字段)
注意:我只是认为它在 ClassLoader
class 是用 Eclipse 编译时有效。我知道的少数差异之一是 Eclipse 编译器似乎还没有遵循 JEP 280。但是 javac
产生的字节码中也有 invokedynamic
指令,所以我怀疑这是问题所在。
你已经指出了正确的方向。当您使用当前版本的 Eclipse 编译 class 时,它会起作用,因为该编译器尚未遵循 JEP 280,因此它不会使用 invokedynamic
进行字符串连接。
这并不意味着在 ClassLoader
中使用 invokedynamic
通常是有问题的。它仅在 java.lang.invoke
程序包引导期间执行的某些关键代码路径中存在问题,显然,此 class 确实在此代码路径上使用了字符串连接。
在 javac
的情况下,您可以通过选项
强制使用旧的字符串连接代码
-XDstringConcat=inline
。查看 JDK 附带的 ClassLoader.class
的字节码,似乎此 class 已使用此选项编译。事实上,查看一些示例,似乎整个 java.base
模块都是使用该选项编译的,与例如相反。 java.desktop
,其 classes 使用 invokedynamic
进行字符串连接。
所以结论是,要在java.base
模块(在OpenJDK和衍生产品中)中修补classes,使用时使用-XDstringConcat=inline
选项编译它们javac
.