我试图理解在尝试序列化/反序列化非常简单的数据结构时出现的以下问题:
case class SimpleClass(i: Int)
object SerializationDebug {
def main(args: Array[String]) {
val c = SimpleClass(0)
val l1 = List(c)
serializationSaveToFile("test", l1)
val l2 = serializationLoadFromFile("test") // .asInstanceOf ...
}
def serializationSaveToFile(fn: String, o: Any) {
val fos = new FileOutputStream(fn)
val oos = new ObjectOutputStream(fos)
oos.writeObject(o)
oos.close()
}
def serializationLoadFromFile(fn: String): Any = {
val fis = new FileInputStream(fn)
val ois = new ObjectInputStream(fis)
return ois.readObject()
}
}
尝试运行此代码时,我在反序列化步骤中得到java.lang.ClassNotFoundException: SimpleClass
。我目前的调查结果如下:
SimpleClass
时,该示例有效,即我可以毫无问题地反序列化List[Int]
或List[(Int, Double)]
。将内置类型与我的SimpleClass
混合(即具有List[Any]
)会再次引发异常。SimpleClass
(例如嵌套在对象或本地范围内),但这并没有改变任何东西。此外,扩展Serializable
的普通(非案例)类会产生相同的结果。Array[SimpleClass]
代替List
确实有效!尝试其他容器可以确认这种奇怪的不一致:在不可变映射中使用SimpleClass
作为类型参数,如果是可变映射,我会得到异常。如果重要:我的Scala版本是2.10.0; JDK是1.7.0。
这里发生了什么?这应该是失败还是某种错误?我手边的实际问题涉及更复杂的数据结构(大量嵌套;内置类和自有类的混合)。任何以最小侵入式简单方式序列化/反序列化此数据结构的建议(即无需找到容器类及其类型参数的工作组合)也是受欢迎的!
答案 0 :(得分:7)
这个解决方案适用于我:
val ois = new ObjectInputStream(new FileInputStream(fileName)) {
override def resolveClass(desc: java.io.ObjectStreamClass): Class[_] = {
try { Class.forName(desc.getName, false, getClass.getClassLoader) }
catch { case ex: ClassNotFoundException => super.resolveClass(desc) }
}
}
当然,在编写对象时,我们使用相同的方式:
val ois = new ObjectOutputStream(new FileOutputStream(path))
ois.writeObject(myobject)
答案 1 :(得分:1)
@trenobus @ bluenote10与您的发现相关:
我今天遇到了这个问题,我认为这是因为当你在控制台中定义它时,类的名称是不同的(损坏的)。例如,我从scala
序列化了一个类One
> import java.io._
import java.io._
> case class One(s: String, b: Boolean)
defined class One
> new ObjectOutputStream(new FileOutputStream("data")) writeObject One("abc", true)
然后我尝试在同一个文件中用java反序列化它,在顶层准备了一个名为One
的类似的类(我使SerialVersionUIDs也是一样的,因为它没有在这里包含它这很重要,但得到了这个错误:
Exception in thread "main" java.lang.ClassNotFoundException: $line4.$read$$iw$$iw$One
建议scala(正确地)每次定义一个类时都会创建一个新的JVM类,并且可能保留一个内部映射,以便您可以通过其定义的名称(One
)来引用它。
同样,因为每个这样的类在JVM中是不同的,如果你在同一个scala控制台中重新定义类One
,然后尝试从data
文件反序列化,你将得到一个原始类(不是您重新定义的新类)。
答案 2 :(得分:-1)
如果SimpleClass扩展Serializable。