我从斯卡拉 - 2.9序列化出一个相当复杂的对象图,我需要读取到斯卡拉2.10。 然而,深某处对象图斯卡拉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]
...
什么是这个序列化对象加载到斯卡拉2.10最简单的方法? 对象使用Scala-2.9正确反序列化,但看起来事情在标准库中已经搬来搬去。 大多数成员scala.collection.JavaConversions
现在在scala.collection.convert.Wrappers
展望未来,我无需显式地指定为每个参与类的序列化也有兴趣在持续大量复杂的对象图的更稳健的方式。
请不要downvote作为一个下意识的,但我的想法是在一个类加载器(上斯卡拉2.9)反序列化,转换成Java集合,然后在第二类加载器(与2.10的类路径上)从Java转换回到阶。
换句话说,Java是通用格式(Java运行时是常见的两种类加载器)。
(或者,而不是两个类加载器,尝试序列化java的形式,然后斜切回来。)
我觉得这正好给理查德#6。 它不必是完全Java核心,只有什么是兼容的。
我会尽力一间休息的时候拿出一个例子,但当然,需要注意的是,该不兼容在于收集和不收集的东西。
这可能会炸毁你的脸,但你可以尝试把2.9斯卡拉-library.jar放在classpath 2.10斯卡拉 - library.jar之后。 然后,类加载器应该找到
scala.collection.JavaConversions$SeqWrapper
,但如果序列化去,一路过关斩将我会感到惊讶?
你应该考虑只用序列化或GSON杰克逊或升JSON或任何以JSON。 这是乏味的,但你这样做一次,它的完成,它会与其他语言工作过 - 你的“快速”解决方案将意味着经常性疼痛向前......
祝好运!
鲁本
所以这是最终为我工作,感谢@ 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做类和间接使用ClassLoaderObjectStream Apache的风景,即使这是简单推出自己的。 我不是那快乐的,我不得不让我自己SeqWrapper的副本(这竟然是在我的文件中唯一有问题的类),但在斯卡拉2.10的包装类scala.collection.convert.Wrappers
有不同SerialVersionUIDs比2.9的相应类别scala.collection.JavaConversions
即使源文本上是相同的。 我原本想只是重定向到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()
}
}
}
}
这让我读无一例外的序列化的文件,但被以这种方式读取的对象是不完整的。 (如果这种方式工作,有不止一个问题类的文件,我真的需要为SerialVersionUIDs查找表,但这是题外话)。 如果有人知道的方式设置的serialVersionUID在了Javassist生成的类不破坏任何其他别的东西,我想听到它。
文章来源: Deserialization throws 'ClassNotFoundException: JavaConversions$SeqWrapper' in Scala 2.10