4

我有一个来自旧 Java 代码的对象,现在我更改了序列化的对象代码。我希望能够同时读取旧文件和新文件。我需要 readObject 中的分支语句来执行以下操作:

if (next object is int -- just poking, it might be an Object)
{
    // we know we are in version 1
} else {
    // read new version of object
}

那有可能吗?

4

4 回答 4

2
if (object instanceof Integer) {
  ... Do stuff
} else {
  ... Do other stuff
}

编辑:我想我应该对此进行扩展。您可以使用检查对象类型,instanceof但我不确定是否能够使用intchar.

于 2012-05-22T14:49:55.547 回答
1

最简单的方法是保留旧的成员变量和它们的旧类型,并为新类型添加新的成员变量。此外,您必须保持类的 serialVersionUID 相同。然后,您的 readObject() 实现可以进行任何必要的操作以将旧数据转换为新数据。

原始对象:

public class MyObject {
   private static final long serialVersionUID = 1234L;

   private int _someVal;
}

新版本:

public class MyObject {
   private static final long serialVersionUID = 1234L;

   private int _someVal;  //obsolete
   private String _newSomeVal;

    private void readObject(java.io.ObjectInputStream in)
      throws IOException, ClassNotFoundException
    {
      in.defaultReadObject();

      if(_someVal != 0) {
        // translate _someVal to _newSomeVal
      }
    }
}

我相信使用 customObjectStreamField[] serialPersistentFields和.ObjectInputStream.GetFieldObjectOutputStream.PutField

于 2012-05-22T15:39:42.833 回答
1

好的,所以基本上问题是“我们如何检查ObjectInputStream下一个字段是原始字段还是对象?” 据我所知,答案是:你不能。

这意味着我能看到的保持向后兼容性的最佳解决方案是永远不要从原始版本中删除原语 - 保留无用的信息会稍微扩大大小,但否则这很容易。

要添加新字段,我可以看到两种方法:

  1. 保持之前的消息格式相同,只在最后添加新对象 - 然后您可以通过消息大小轻松区分不同版本(或者更准确地说,当您获得 v1 对象时读取 v2 的数据时您将获得 IOException)。这要简单得多,而且通常是首选。

  2. 您可以将对象从 v1 更改为 v2,然后进行简单instanceof检查。如果要添加原语是存储它们的包装器版本(即Integer等)。可以为您节省一些字节,但 Java 的序列化协议从一开始就效率不高,所以这实际上是不必要的复杂。

于 2012-05-22T15:40:58.763 回答
0

ObjectInputStream将加载并创建正确类的实例。

object = ois.readObject();

if (object instanceof YourNewShiny ){
    // new style object
} else if (object instanceof YourOldBusted ){
    // convert YourOldBusted to YourNewShiny
} else {
    throw new ToyOutOfPram();
}

如果您有一个新类,这一切都很好,但是如果您以不兼容的方式更改了您的类,以至于ObjectInputStream无法将类的旧版本反序列化为新形式。如果是这种情况,你就吃饱了。

选项:

  • 还原您的更改,或者以兼容的方式进行更改,即添加一个 serialVersionId,不要更改字段的顺序,只添加新字段,另外不要假设非空约束
  • 使用旧版本的代码读取序列化数据,将其转换为某种中间形式(xml、csv 等),然后将此数据导入新的类定义并序列化
  • 手动重新实现ObjectInputStream以检测您的类类型(您可以使用 serialVersionId 来加强类型)

只有第一个对我来说似乎是个好主意。

于 2012-05-22T15:42:45.937 回答