scala.tools.reflect.ToolBoxError: сбой рефлексивной компиляции: невозможно инициализировать компилятор из-за java.lang.VerifyError

Я хочу передать файл scala, содержащий класс case, чтобы мое приложение скомпилировало этот класс case во время выполнения и начало его использовать.

Основная причина, по которой я это делаю, заключается в том, что я не хочу перестраивать свой код каждый раз, когда изменяется класс case. Так что было бы лучше передать его как параметр (если вам интересно, операции с этим классом case являются общими, поэтому никаких доработок в преобразованиях не требуется)

Я использовал эти post1, post2 и post3 как Рекомендации. Пока мое приложение выглядит так:

import scala.io.Source
import scala.reflect.runtime.universe
import scala.tools.reflect._

object TestCompile {
  def main(args: Array[String]): Unit = {

    val path = "C:\\myWorkspace\\entity\\TestClass.scala"
    val tb = universe.runtimeMirror(getClass.getClassLoader).mkToolBox()
    val src = Source.fromFile(path).mkString.stripMargin
    val clazz = tb.compile(tb.parse(src))().asInstanceOf[Class[_]]

  }
}

Файл TestClass.scala выглядит следующим образом:

case class TestClass(
         val value : String,
         val timeStamp : Long,
         val rowKey : String,
         val columnFamily : String
)

Но я получаю исключение в

val clazz = tb.compile(tb.parse(src))().asInstanceOf[Class[_]]

Исключение:

Исключение в потоке "main" scala.tools.reflect.ToolBoxError: сбой рефлексивной компиляции: невозможно инициализировать компилятор из-за java.lang.VerifyError: scala/tools/reflect/ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal at scala.tools.reflect.ToolBoxFactory $ToolBoxImpl$withCompilerApi$api$.liftedTree1$1(ToolBoxFactory.scala:344) в scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$withCompilerApi$api$.compiler$lzycompute(ToolBoxFactory.scala:330) в scala.tools.reflect. ToolBoxFactory$ToolBoxImpl$withCompilerApi$api$.compiler(ToolBoxFactory.scala:329) в scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$withCompilerApi$.liftedTree2$1(ToolBoxFactory.scala:356) в scala.tools.reflect.ToolBoxFactory$ToolBoxImpl $withCompilerApi$.apply(ToolBoxFactory.scala:354) в scala.tools.reflect.ToolBoxFactory$ToolBoxImpl.parse(ToolBoxFactory.scala:413) в TestCompile$.main(App.scala:17) в TestCompile.main(App. scala) Причина: java.lang.VerifyError: scala/tools/ Reflect/ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal в scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$withCompilerApi$api$.liftedTree1$1(ToolBoxFactory.scala:334)

Ниже приведена зависимость, которую я использую, однако я пытался использовать другие версии, всегда получая ту же ошибку:

<dependency>
  <groupId>org.scala-lang</groupId>
  <artifactId>scala-reflect</artifactId>
  <version>2.11.6</version>
</dependency>

Что я делаю не так?


person Ignacio Alorre    schedule 09.01.2020    source источник


Ответы (3)


Я не могу воспроизвести VerifyError.

У меня есть

java.lang.ClassCastException: scala.runtime.BoxedUnit cannot be cast to java.lang.Class

в строке val clazz = tb.compile(tb.parse(src))().asInstanceOf[Class[_]].

tb.compile(tb.parse(src)) имеет тип () => Any, поэтому tb.compile(tb.parse(src))() имеет тип Any.

https://github.com/scala/scala/blob/2.13.x/src/compiler/scala/tools/reflect/ToolBox.scala#L129

Удалить .asInstanceOf[Class[_]].

Также см. Причины получения java.lang.VerifyError

person Dmytro Mitin    schedule 09.01.2020

У меня есть немного времени, чтобы проверить это сегодня. Я думаю, что основная проблема заключается в том, что последняя ожидаемая строка scala.reflect.classTag[TestClass].runtimeClass отсутствует в TestClass.scala.

Еще одна важная вещь, которую следует помнить, это то, что scala-compiler.jar также должен быть в вашем пути к классам.

Как только я решил это, я столкнулся с другой проблемой с преобразованием объектов Java/Scala. У вас есть два варианта: сделать поле timeStamp либо String, либо Java.lang.Long. Поскольку преобразование строки тривиально, ниже я привел пример для Java.lang.Long.

С указанными выше изменениями мой TestClass.scala выглядит следующим образом:

case class TestClass(
                      value : String,
                      timeStamp : java.lang.Long,
                      rowKey : String,
                      columnFamily : String
                    ) {}

scala.reflect.classTag[TestClass].runtimeClass

Я скопировал его в каталог /tmp/ для тестирования.

Тестирование

Мой TestCompile.scala выглядит следующим образом:

import scala.io.Source
import scala.reflect.runtime.universe
import scala.tools.reflect._

object TestCompile {
  def main(args: Array[String]): Unit = {

    val path = "/tmp/TestClass.scala"
    val tb = universe.runtimeMirror(getClass.getClassLoader).mkToolBox()
    val src = Source.fromFile(path).mkString.stripMargin
    println(src)
    val clazz = tb.compile(tb.parse(src))().asInstanceOf[Class[_]]

    val ctor = clazz.getDeclaredConstructors()(0)
    val instance = ctor.newInstance("My value", new java.lang.Long(1234567890L), "Row1", "Column1")
    println(instance.toString)

  }
}

Выход

TestClass(My value,1234567890,Row1,Column1)
person vsnyc    schedule 22.01.2020

Поскольку вы потеряли зависимость, добавьте эту зависимость в свой pom.xml.

<dependency>
    <groupId>org.scala-lang</groupId>
    <artifactId>scala-library</artifactId>
    <version>2.11.8</version>
</dependency>
<dependency>
    <groupId>org.scala-lang</groupId>
    <artifactId>scala-reflect</artifactId>
    <version>2.11.8</version>
</dependency>
<dependency>
    <groupId>org.scala-lang</groupId>
    <artifactId>scala-compiler</artifactId>
    <version>2.11.8</version>
</dependency>

введите здесь описание изображения

person Barca    schedule 20.07.2021