使用 Scala 编译器本地构建的运行时异常:"java.lang.NoSuchMethodError: 'boolean java.lang.StringBuilder.isEmpty()'"



我有一个scala编译器的本地版本。当我在另一个Scala应用程序中使用我构建的编译器(编译器/反射/库(的三个jar时,我得到了以下异常(http://ikojo.in/):

[Thu Aug 25 11:24:22 EDT 2022, Utils] SEVERE: Problem
java.lang.NoSuchMethodError: 'boolean java.lang.StringBuilder.isEmpty()'
at scala.tools.nsc.ast.parser.Scanners$Scanner.checkNoTrailingSeparator(Scanners.scala:1264)
at scala.tools.nsc.ast.parser.Scanners$Scanner.getNumber(Scanners.scala:1302)
at scala.tools.nsc.ast.parser.Scanners$Scanner.fetchToken(Scanners.scala:632)
at scala.tools.nsc.ast.parser.Scanners$Scanner.nextToken(Scanners.scala:422)
...
at scala.tools.nsc.Global$GlobalPhase.run(Global.scala:401)
at scala.tools.nsc.Global$Run.compileUnitsInternal(Global.scala:1519)
at scala.tools.nsc.Global$Run.compileUnits(Global.scala:1503)
at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.compile(IMain.scala:744)
at scala.tools.nsc.interpreter.IMain$Request.$anonfun$compile$7(IMain.scala:978)
at scala.runtime.java8.JFunction0$mcZ$sp.apply(JFunction0$mcZ$sp.scala:17)
at scala.tools.nsc.interpreter.IMain$.withSuppressedSettings(IMain.scala:1407)

请注意,Java Runtime8是此堆栈跟踪中的调用程序。异常发生在编译器代码本身的早期:在编译器的第一个阶段,即语法分析器,在23个(或更多(阶段中。

还要注意,我的编译器本地构建的代码与官方scala版本相同(来自:https://github.com/scala/scala/releases/tag/v2.13.6)。

我检查了一个相关问题的答案java.lang.NoSuchMethodError:java.lang.String.isEmpty((Z,但似乎没有一个好的答案,或者至少我不清楚

有人对如何调试或解决这个问题有任何提示或线索吗?

在15之前的Java版本中,java.lang.StringBuilder没有isEmpty方法;Java 15之后的Java版本具有isEmpty方法。

Scala编译器的代码有一个StringBuilderOps隐式类,它有一个isEmpty方法。

因此,当使用15之前的Java版本编译Scala编译器时,编译器会看到(在第1264行(我们在StringBuilder上调用isEmpty方法。由于java.lang.StringBuilder上没有isEmpty方法,编译器会查找一个StringBuilder可以隐式转换为具有isEmpty方法的类。如果正好有一个这样的类(在这种情况下是StringBuilderOps(,那么编译器说";这不是一个错误";并用类似的东西有效地替换CCD_ 13调用

  • (new StringBufferOps(cbuf)).isEmpty,或
  • StringBufferOps$.isEmpty(cbuf)

(两者实际上是一样的:第二个被设置为静态调用,可能是因为StringBufferOps扩展了AnyVal而生成的(。注意,这不会导致对StringBufferOps上的isEmpty的调用。

如果构建编译器的Java版本是Java 15或更高版本,那么编译器会发现StringBuilder上有一个isEmpty方法,最终在发出Java字节码时,它会发出在JVM中的StringBuilder上调用isEmpty方法的常用代码。

因为java.lang和类似的包是由Java运行时提供的,所以它们不包含在jar文件中。因此,如果在Java 15之前的JVM上运行生成的jar文件,那么字节码中会引用一个不存在的方法,JVM会抛出NoSuchMethodError

至少目前,我不相信Scala编译器正式支持使用Java 8或Java 11以外的Java版本构建。如果使用更高版本进行构建,请注意不要将构建的编译器与早期的Java版本一起使用。

导致错误的Java版本如下:
ben@Bulents-MacBook-Pro ~ % java -version
java -version
java version "15.0.1" 2020-10-20
Java(TM) SE Runtime Environment (build 15.0.1+9-18)
Java HotSpot(TM) 64-Bit Server VM (build 15.0.1+9-18, mixed mode, sharing)

相反,当我用以下代码编译scala编译器时,错误得到了解决:

ben@Bulents-MacBook-Pro ~ % java -version
java -version
java version "1.8.0_271"
Java(TM) SE Runtime Environment (build 1.8.0_271-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.271-b09, mixed mode)

我不知道为什么或如何运作,但确实如此。我有一些猜测,但是,他们没有受过很好的教育。所以,如果有人有更深入的见解,请分享。非常感谢。

相关内容

最新更新