在Scala2.12中,为什么运行时创建的TypeTag都不可序列化?
我正在寻找一种方法来创建一个可序列化的TypeTag,而不使用编译时工具(完全依赖于运行时)。这是所有反思性语言的基本特征 这篇文章的答案提出了几种方法: 他们没有一个成功:在Scala2.12中,为什么运行时创建的TypeTag都不可序列化?,scala,reflection,types,scala-reflect,scala-2.12,Scala,Reflection,Types,Scala Reflect,Scala 2.12,我正在寻找一种方法来创建一个可序列化的TypeTag,而不使用编译时工具(完全依赖于运行时)。这是所有反思性语言的基本特征 这篇文章的答案提出了几种方法: 他们没有一个成功: package com.tribbloids.spike.scala_spike import java.io.{ ByteArrayInputStream, ByteArrayOutputStream, ObjectInputStream, ObjectOutputStream } import o
package com.tribbloids.spike.scala_spike
import java.io.{
ByteArrayInputStream,
ByteArrayOutputStream,
ObjectInputStream,
ObjectOutputStream
}
import org.apache.spark.sql.catalyst.ScalaReflection
import org.apache.spark.sql.catalyst.ScalaReflection.universe
import org.scalatest.FunSpec
class TypeTagFromType extends FunSpec {
import ScalaReflection.universe._
it("create TypeTag from reflection") {
val ttg = typeTag[String]
val ttg2 = TypeUtils.createTypeTag_fast(ttg.tpe, ttg.mirror)
val ttg3 = TypeUtils.createTypeTag_slow(ttg.tpe, ttg.mirror)
Seq(
ttg -> "from static inference",
ttg2 -> "from dynamic type - fast",
ttg3 -> "from dynamic type - slow"
).map {
case (tt, k) =>
println(k)
try {
val bytes = serialise(tt)
val tt2 = deserialise(bytes)
assert(tt.tpe =:= tt2.tpe)
} catch {
case e: Throwable =>
e.printStackTrace()
}
}
}
def serialise(tt: universe.TypeTag[_]): Array[Byte] = {
val bos = new ByteArrayOutputStream()
try {
val out = new ObjectOutputStream(bos)
out.writeObject(tt)
out.flush()
val array = bos.toByteArray
array
} finally {
bos.close()
}
}
def deserialise(tt: Array[Byte]): TypeTag[_] = {
val bis = new ByteArrayInputStream(tt)
try {
val in = new ObjectInputStream(bis)
in.readObject().asInstanceOf[TypeTag[_]]
} finally {
bis.close()
}
}
}
object TypeUtils {
import ScalaReflection.universe._
def createTypeTag_fast[T](
tpe: Type,
mirror: Mirror
): TypeTag[T] = {
TypeTag.apply(
mirror,
NaiveTypeCreator(tpe)
)
}
def createTypeTag_slow[T](
tpe: Type,
mirror: Mirror
): TypeTag[T] = {
val toolbox = scala.tools.reflect.ToolBox(mirror).mkToolBox()
val tree = toolbox.parse(s"scala.reflect.runtime.universe.typeTag[$tpe]")
val result = toolbox.eval(tree).asInstanceOf[TypeTag[T]]
result
}
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]
}
}
}
ttg3
遇到错误:
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)
...
java.lang.ClassNotFoundException: __wrapper$1$71de08de01364321af52d1563247025d.__wrapper$1$71de08de01364321af52d1563247025d$$typecreator1$1
at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:686)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1868)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1751)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2042)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1573)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2287)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2211)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2069)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1573)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:431)
...
如果您熟悉scala反射的设计,您能给出一个“规范”实现来产生一个功能性的TypeTag吗?序列化“类型”的目标是什么?在分布式计算中使用它,当许多数据共享同一类型时,通常不共享类型定义,据我所知,通过共享模式或类似的东西,
TypeTag
是Scala非常独特的一个特性,用于将类型信息从编译时传输到运行时。因此,我不确定在运行时创建TypeTag
是否是所有具有反射功能的语言的基本功能。也就是说,TypeTag
是由本质上相当于隐式宏的内容生成的。我想您应该能够编写“宏”手动生成的调用。此外,您似乎还想从类型创建类型标签
。但是如果你已经有了类型
对象,为什么你仍然需要类型标签
,它提供的功能比进入类型
多一点?序列化“类型”的目标是什么?在分布式计算中使用它,当许多数据共享同一类型时,类型定义通常不会共享,据我所知,通过共享模式或类似的东西,TypeTag
是Scala非常独特的一个特性,用于将类型信息从编译时传输到运行时。因此,我不确定在运行时创建TypeTag
是否是所有具有反射功能的语言的基本功能。也就是说,TypeTag
是由本质上相当于隐式宏的内容生成的。我想您应该能够编写“宏”手动生成的调用。此外,您似乎还想从类型创建类型标签
。但是,如果您已经有了类型
对象,为什么还需要类型标签
,它提供的功能比进入类型
多一点?