Scala反序列化:找不到类

时间:2013-05-05 15:47:51

标签: scala serialization deserialization scala-2.10

我试图理解在尝试序列化/反序列化非常简单的数据结构时出现的以下问题:

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。

这里发生了什么?这应该是失败还是某种错误?我手边的实际问题涉及更复杂的数据结构(大量嵌套;内置类和自有类的混合)。任何以最小侵入式简单方式序列化/反序列化此数据结构的建议(即无需找到容器类及其类型参数的工作组合)也是受欢迎的!

3 个答案:

答案 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。