我有一个从Scala-2.9序列化出来的相当复杂的对象图,我需要将它读入Scala-2.10。然而,在对象图的某处,Scala-2.10抛出了:
! java.lang.ClassNotFoundException: scala.collection.JavaConversions$SeqWrapper
! at java.net.URLClassLoader$1.run(URLClassLoader.java:366) ~[na:1.7.0_21]
! at java.net.URLClassLoader$1.run(URLClassLoader.java:355) ~[na:1.7.0_21]
! at java.security.AccessController.doPrivileged(Native Method) ~[na:1.7.0_21]
! at java.net.URLClassLoader.findClass(URLClassLoader.java:354) ~[na:1.7.0_21]
! at java.lang.ClassLoader.loadClass(ClassLoader.java:423) ~[na:1.7.0_21]
! at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) ~[na:1.7.0_21]
! at java.lang.ClassLoader.loadClass(ClassLoader.java:356) ~[na:1.7.0_21]
! at java.lang.Class.forName0(Native Method) ~[na:1.7.0_21]
! at java.lang.Class.forName(Class.java:266) ~[na:1.7.0_21]
! at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:623) ~[na:1.7.0_21]
...将这个序列化对象加载到Scala-2.10中最简单的方法是什么?使用Scala-2.9可以正确地对对象进行反序列化,但看起来在标准库中发生了变化。scala.collection.JavaConversions的大多数成员现在都在scala.collection.convert.Wrappers中
展望未来,我还对持久化大型复杂对象图的更健壮的方法感兴趣,而不必显式地为所涉及的每个类指定序列化。
发布于 2013-06-30 05:01:52
所以,这就是最终为我工作的方法,感谢@som snytt为我指明了正确的方向:
object MyWrappers {
import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc }
import scala.collection.convert._
import WrapAsScala._
import WrapAsJava._
import Wrapper._
@SerialVersionUID(3200663006510408715L)
case class SeqWrapper[A](underlying: Seq[A]) extends ju.AbstractList[A] with Wrappers.IterableWrapperTrait[A] {
def get(i: Int) = underlying(i)
}
}
import org.apache.commons.io.input.ClassLoaderObjectInputStream
object Loader extends ClassLoader {
override def loadClass(name: String) : Class[_] = {
import javassist._
try super.loadClass(name)
catch {
case e: ClassNotFoundException if name.startsWith("scala.collection.JavaConversions") => {
val name2 = name.replaceFirst("scala.collection.JavaConversions",
"MyWrappers")
val cls = ClassPool.getDefault().getAndRename(name2, name)
cls.toClass()
}
}
}
}
val objectStream = new ClassLoaderObjectInputStream(Loader, stream)
objectStream.readObject()这允许我将原始的2.9序列化文件直接读入2.10,而无需重新序列化。它依赖Javassist来实现类的间接寻址,并使用来自Apache Commons的ClassLoaderObjectStream,尽管这可以很容易地实现您自己的。我不是很高兴不得不制作自己的SeqWrapper副本(这是我的文件中唯一有问题的类),但是scala-2.10的scala.collection.convert.Wrappers中的包装类与2.9的scala.collection.JavaConversions中的相应类具有不同的SerialVersionUID,尽管它们的源代码在文本上是相同的。我最初尝试只重定向到scala.collection.convert.Wrappers,并使用Javassist设置SerialVersionUID:
object Loader extends ClassLoader {
override def loadClass(name: String) : Class[_] = {
import javassist._
try super.loadClass(name)
catch {
case e: ClassNotFoundException if name.startsWith("scala.collection.JavaConversions") => {
val name2 = name.replaceFirst("JavaConversions", "convert.Wrappers")
val cls = ClassPool.getDefault().getAndRename(name2, name)
cls.addField(CtField.make("private static final long serialVersionUID = 3200663006510408715L;", cls))
cls.toClass()
}
}
}
}这允许我无异常地读取序列化文件,但以这种方式读取的对象是不完整的。(如果这种方法有效,并且文件中有多个问题类,我真的需要SerialVersionUID的查找表,但这不是重点)。如果有人知道一种方法,在不破坏任何其他东西的情况下在Javassist生成的类上设置SerialVersionUID,我很乐意听到。
发布于 2013-06-25 00:16:31
想法,没有真正的帮助:
Scala
数据类型的东西--
发布于 2013-06-27 06:25:04
请不要下意识地反对,但我的想法是在一个类加载器(在scala 2.9上)中反序列化,转换成一个java集合,然后在第二个类加载器(类路径上有2.10 )中从java转换回scala。
换句话说,java是通用格式( java运行时对两个类加载器都是通用的)。
(或者,不使用两个类加载器,而是尝试序列化java表单,然后再将其还原。)
我认为这是Richard的第6条,它不一定要完全是java内核,只需要兼容的就行了。
我将尝试在喝咖啡休息时提供一个示例,但当然需要注意的是,不兼容性取决于收集的内容,而不是收集的内容。
https://stackoverflow.com/questions/17246409
复制相似问题