【问题标题】:Patching java.base results in java.lang.LinkageError修补 java.base 会导致 java.lang.LinkageError
【发布时间】:2019-07-05 05:58:30
【问题描述】:

我正在尝试在 Java 11 中做同样的事情,这可以在 pre java 9 中使用 -Xbootclasspath/p:path 完成。

作为一个简单的例子,我修改了java.lang.IntegervalueOf 方法之一并编译了项目:

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 进行更改。我的补丁文件夹中该类的绝对存在似乎引发了这个错误。 (我只想在类的底部添加一个字段)

注意:我只是认为当ClassLoader 类使用 Eclipse 编译时它可以工作。我知道的少数区别之一是 Eclipse 编译器似乎还没有遵循JEP 280。但是javac 产生的字节码中也有invokedynamic 指令,所以我怀疑这是问题所在。

【问题讨论】:

  • Dp 分享你对ClassLoader 所做的更改,你试图用它来修补现有模块。
  • @nullpointer 我尝试了各种更改,最初我想简单地添加一个字段并更改 loadClass 中的某些内容。但我只是认为只有文件夹中的类就足以出现此错误,无需更改。
  • @ZhekaKozlov 感谢您的评论,但我相信您在功能上谈论的是前者java.endorsed.dirs,不是吗?我没有在任何地方读到不允许修补 java.base。事实上,它甚至取决于所使用的编译器,正如您从上面的描述中看到的那样。因此,如果您能分享一些技术细节或链接到确认“您不应该......”的规范,我将不胜感激。
  • 对不起,忘了我说的话。 java.base 确实不是可升级的模块,但这与补丁无关。我混淆了这两个不相关的事情。如果需要,您可以修补 java.base

标签: java classpath java-11 java-module java-platform-module-system


【解决方案1】:

您确实已经指出了正确的方向。当您使用当前版本的 Eclipse 编译该类时,它可以工作,因为该编译器尚未遵循 JEP 280,因此它不使用 invokedynamic 进行字符串连接。

这并不意味着在ClassLoader 中使用invokedynamic 通常是有问题的。只有在 java.lang.invoke 包的引导过程中执行的某些关键代码路径中才会出现问题,并且显然,这个类确实在此代码路径上使用了字符串连接。

如果是javac,您可以通过选项
-XDstringConcat=inline 强制使用旧的字符串连接码。查看 JDK 附带的 ClassLoader.class 的字节码,似乎这个类是用这个选项编译的。事实上,查看一些示例,似乎整个 java.base 模块已使用该选项进行编译,相比之下,例如java.desktop,其类使用invokedynamic 进行字符串连接。

所以结论是,要修补 java.base 模块中的类(在 OpenJDK 和衍生产品中),在使用 javac 时使用 -XDstringConcat=inline 选项编译它们。

【讨论】:

  • 使用-XDstringConcat=inline 编译有效。我不认为这是唯一的原因,因为我在ClassLoader 中看到了其他invokedynamic 指令。但是正如您指出的那样,它们在引导期间不会执行,因此不会引起任何问题。谢谢。
  • 确实,这个标志似乎是专门为 java.base 模块(以及其他几个模块)添加的:hg.openjdk.java.net/jdk/jdk/file/fedc89081b57/make/…
  • @Holger:还有一个与补丁相关的问题:您使用哪个 IDE? Eclipse 似乎还没有很好地支持修补模块(至少在修补 java.base 时没有)。它显示无法解决类或字段等错误(但无论如何都会编译它),当尝试访问从另一个修补类添加到修补类的新成员时,代码完成不起作用,等等。所有这些都可以,但真的可用但恕我直言.
  • 不幸的是,我不能推荐任何。我主要将 Eclipse 与非模块化软件一起使用。我也在使用 Netbeans,但我对它的质量不满意,尤其是在 Apache 基金会维护之后。我仍然希望有一个更好的未来版本,但也许,我会尝试一下 IntelliJ。如前所述,目前,这不是我的主要关注点,所以我无法提供有根据的建议。
  • @Holger 好的,谢谢。这里也一样,主要是 Eclipse。但是对于模块(尤其是补丁),它仍然很糟糕。刚开了一个bug
猜你喜欢
  • 1970-01-01
  • 2015-10-18
  • 1970-01-01
  • 1970-01-01
  • 2023-04-09
  • 1970-01-01
  • 2022-12-16
  • 2013-12-26
  • 1970-01-01
相关资源
最近更新 更多