Как в Scala создать TypeTag из сериализуемого типа?

В отражении Scala TypeTag обычно может быть создан из Type с помощью TypeCreator:

object TypeUtils {

  import ScalaReflection.universe._

  def createTypeTag[T](
      tpe: Type,
      mirror: reflect.api.Mirror[reflect.runtime.universe.type]
  ): TypeTag[T] = {
    TypeTag.apply(
      mirror,
      NaiveTypeCreator(tpe)
    )
  }

  case class NaiveTypeCreator(tpe: Type) extends reflect.api.TypeCreator {

    def apply[U <: reflect.api.Universe with Singleton](
        m: reflect.api.Mirror[U]): U#Type = {
      //          assert(m eq mirror, s"TypeTag[$tpe] defined in $mirror cannot be migrated to $m.")
      tpe.asInstanceOf[U#Type]
    }
  }

К сожалению, оказывается, что вывод createTypeTag не сериализуем, в отличие от typeTag, созданного на основе вывода во время компиляции:

import java.io.{ByteArrayOutputStream, ObjectOutputStream}

import org.apache.spark.sql.catalyst.ScalaReflection
import org.scalatest.FunSpec

class TypeTagFromType extends FunSpec {

  import ScalaReflection.universe._

  it("create TypeTag from reflection") {

    val ttg = typeTag[String]

    val ttg2 = TypeUtils.createTypeTag(ttg.tpe, ttg.mirror)

    Seq(
      ttg -> "from static inference",
      ttg2 -> "from dynamic type"
    ).foreach {
      case (tt, k) =>
        println(k)

        val bos = new ByteArrayOutputStream()
        try {
          val out = new ObjectOutputStream(bos)
          out.writeObject(tt)
          out.flush()
          val array = bos.toByteArray
        } finally {
          bos.close()
        }
    }
  }
}

Это дает результат:

from static inference
from dynamic type


scala.reflect.runtime.JavaMirrors$JavaMirror$$anon$2
java.io.NotSerializableException: scala.reflect.runtime.JavaMirrors$JavaMirror$$anon$2
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)

Указывает, что второй TypeTag не является сериализуемым, а первый — сериализуемым.

Итак, мой вопрос: как сделать второй TypeTag сериализуемым, как первый?

На данный момент я использую scala 2.12.10.


person tribbloid    schedule 23.12.2019    source источник


Ответы (1)


На основе Как создать TypeTag вручную?

если вам нужен сериализуемый TypeTag и производительность не является вашей главной задачей

тогда подумайте

import scala.reflect.runtime.universe._
import scala.reflect.runtime.currentMirror
import scala.tools.reflect.ToolBox

def createTypeTag(tp: Type): TypeTag[_] = {
  val toolbox = universe.runtimeMirror(getClass.getClassLoader).mkToolBox()
  val ttree = toolbox.parse(s"scala.reflect.runtime.universe.typeTag[$tp]")
  toolbox.eval(ttree).asInstanceOf[TypeTag[_]]
}

val ttg = typeTag[List[String]]
val ttg2 = createTypeTag(ttg.tpe)
...
person Mario Galic    schedule 23.12.2019
comment
Я считаю, что этот ответ устарел. Зеркальный класс не имеет метода mkToolBox и вызывает ошибку компиляции. Я спрошу еще раз под новым заголовком, так как этот помечен как дублированный - person tribbloid; 24.12.2019
comment
@tribbloid Ответ не устарел. Код компилируется в 2.12.10, 2.13.1. Вам просто нужен еще один импорт import scala.reflect.runtime.universe (помимо import scala.reflect.runtime.universe._). mkToolBox находится в ToolBoxFactory здесь github.com/scala/scala/blob/2.13.x/src/compiler/scala/tools/ А неявное преобразование из Mirror в ToolBoxFactory здесь github.com/scala/scala/blob/2.13.x/src/compiler/ скала/инструменты/ - person Dmytro Mitin; 24.12.2019
comment
Я вижу, спасибо большое! Дай мне попробовать - person tribbloid; 24.12.2019
comment
Хорошо работает! Но все же я немного разочарован тем, что такая простая вещь должна выполняться с помощью манипуляций со строками. - person tribbloid; 24.12.2019
comment
К сожалению, только что обнаружил, что сериализация работает, но десериализация не работает: java.lang.ClassNotFoundException: __wrapper$1$2044369228ff48bb85c06775c7f0d775.__wrapper$1$2044369228ff48bb85c06775c7f0d775$$typecreator1$1 - person tribbloid; 24.12.2019
comment
Уже задал новый вопрос по предложению, большое спасибо за вашу помощь! stackoverflow.com/questions/59473734/ - person tribbloid; 25.12.2019