我有一个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版本一起使用。
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)
我不知道为什么或如何运作,但确实如此。我有一些猜测,但是,他们没有受过很好的教育。所以,如果有人有更深入的见解,请分享。非常感谢。