6

我试图了解尝试序列化/反序列化非常简单的数据结构时发生的以下问题:

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)]没有问题。将内置类型与 my SimpleClass(即具有 a List[Any])再次混合会引发异常。
  • 我试图SimpleClass在其他范围内定义(例如嵌套在对象或本地范围内),但这并没有改变任何东西。此外,扩展普通(非大小写)类Serializable会产生相同的结果。
  • 更令人费解的是,使用Array[SimpleClass]而不是List确实有效!尝试其他容器证实了这种奇怪的不一致:SimpleClass在不可变映射中使用类型参数是可行的,如果是可变映射,我会遇到异常。

以防万一:我的 Scala 版本是 2.10.0;JDK 是 1.7.0。

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

4

3 回答 3

8

这个解决方案对我来说很好:

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)
于 2014-03-13T10:12:18.573 回答
1

@trenobus @bluenote10 与您的发现相关:

我今天刚刚遇到这个问题,我认为这是因为当你在控制台中定义它时,类的名称是不同的(损坏的)。例如,我One从 scala序列化了一个类

> 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 中都是不同的,如果你One在同一个 scala 控制台中重新定义类,然后尝试从data文件中反序列化,你会得到一个原始类的对象(不是你重新定义的新类) .

于 2013-09-03T17:12:24.870 回答
-1

如果 SimpleClass 扩展 Serializable 则有效。

于 2013-05-05T17:13:07.150 回答