当类字段的数据类型改变时,处理反序列化



我有一个可序列化的类。

public class Customer  implements Externalizable {
private static final long serialVersionUID = 1L;
    private String id;
    private String name;
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public  String getName() {
        return name;
    }

    public void setName( String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "id : "+id+" name : "+name ;
    }
    @Override
    public void readExternal(ObjectInput in) throws IOException,
            ClassNotFoundException {
            this.setId((String) in.readObject());
            this.setName((String) in.readObject());     
    }
    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        System.out.println("Reached here");
        out.writeObject(id);
        out.writeObject(name);
    }

}

我已经将类的对象序列化到一个文件中。现在我已经将name的数据类型从String更改为List。因此,在反序列化时,我得到一个类强制转换异常,因为它无法从字符串转换为列表。我正在考虑更改类的版本,每次对类进行一些更改,以便在readExternal中我可以显式地处理它。然而,虽然这个想法可能适用于简单的类,但对于更大的复杂类就会失败。有谁能提供一个更简单的解决方案吗?

谢谢

您只需要自己管理不同的可能性(并执行适当的转换)。

@Override
public void readExternal(ObjectInput in) throws IOException,
  ClassNotFoundException {
  this.setId((String) in.readObject());
  Object nameField = in.readObject();
  if (nameField != null) {
    boolean resolved = false;
    if (nameField instanceof String) {
      ArrayList<String> list = new ArrayList<String>(); // Or whatever you want to for converting the String to list.
      list.add((String)nameField);
      this.setName(list);
      resolved = true;
    }
    if (nameField instanceof List) {
      this.setName((List<String>) nameField);
      resolved = true;
    }
    if (!resolved) {
      throw new Exception("Could not deserialize " + nameField + " into name attribute");
    }
  }
}

我建议你看看不同的序列化引擎,如Protocol Buffers, Apache Avro或Apache Thrift。

其他可能:在readExternal/writeExternal上使用策略模式选择序列化算法并委托给它。然而,你仍然需要一个"选择器"。类标识符(全名?)和版本通常是首选,但序列化布局(即String + StringString + List)也是一种选择。

您最好实现一个将序列化对象从一个版本转换为另一个版本的迁移工具(通过将其反序列化到旧类的实例,然后创建新类的实例并复制字段)。保持简单,不需要过于聪明的代码。

我还建议不要在readExternal方法实现迁移算法更好的关注点分离,更不用说最有可能提高性能,因为你可以而且应该省略readExternal反序列化提供者通常是做一个很好的工作,除非你不反序列化的对象反复分支(版本x或y ?)将只产生一次"旧"分支,但评估每一个反序列化。最后但并非最不重要的是:你没有的代码就是你不需要维护的代码->提高可维护性。

顺便说一句:serialVersionUID字段的想法是给反序列化实现一个提示,即序列化的对象不能反序列化到同一类的实例,因为它已经更改(从而使其成为具有相同名称的不同类)。如果在进行更改时不更改版本字段,则它完全无用,您可以将其设置为0或任何常量,并且永远不碰它。

最新更新