Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/374.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Java中将类重构为接口时,如何支持向后兼容的序列化?_Java_Serialization_Backwards Compatibility - Fatal编程技术网

在Java中将类重构为接口时,如何支持向后兼容的序列化?

在Java中将类重构为接口时,如何支持向后兼容的序列化?,java,serialization,backwards-compatibility,Java,Serialization,Backwards Compatibility,不幸的是,题名中的情况在过去几年中已经出现 我有一个Id接口,它扩展了Serializable,并包含名称和Id号的getter。有一个匹配的IdImpl类实现该接口。然而,在过去的某个时候,Id是类。还有一个可序列化的容器对象,其成员字段的类型为Id。这些容器对象已经被序列化到数据库好几年了,所以有一些容器对象的版本包含两种类型的Ids。当尝试反序列化旧对象时,我们会得到一个InvalidClassException。如何反序列化包含旧Id具体类实例的旧容器对象 全面披露:多年来,Id接口还做

不幸的是,题名中的情况在过去几年中已经出现

我有一个
Id
接口,它扩展了
Serializable
,并包含名称和Id号的getter。有一个匹配的
IdImpl
类实现该接口。然而,在过去的某个时候,
Id
是类。还有一个可序列化的容器对象,其成员字段的类型为
Id
。这些容器对象已经被序列化到数据库好几年了,所以有一些容器对象的版本包含两种类型的
Id
s。当尝试反序列化旧对象时,我们会得到一个
InvalidClassException
。如何反序列化包含旧
Id
具体类实例的旧容器对象

全面披露:多年来,
Id
接口还做了一些其他更改,但我认为它们看起来像(为
IdImpl
添加了一个字段,为“String idType”为
Id
添加了一个getter;泛化了
Comparable
)。这些变化中的一个也会导致问题吗

这些类看起来像这样:

// current Id interface
public interface Id extends Serializable, Comparable<Id> {
    String getName();
    int getIdNumber();
}

// current Id implementation
public class IdImpl implements Id {
    private static final long serialVersionUID = 10329865109284L;
    private String name;
    private int idNumber;
    IdImpl(String name, int idNumber) { this.name = name; this.idNumber = idNumber; }
    @Override public String getName() { return name; }
    @Override public int getIdNumber() { return idNumber; }
    @Override public int compareTo(Id id) { /* some code here */ }
}

// the container object
public ContainerForm implements Serializable {
    private static final long serialVersionUID = -3294779665912049275L;
    private String someField;
    private Id user;
    private String someOtherField;
    // getters and setters
}

// this is what the _old_ Id concrete class looked like
// (from source control history; not in current project)
public class Id implements Serializable, Comparable {
    // never had a serialVersionUID
    private String name;
    private int idNumber;
    Id(String name, int idNumber) { this.name = name; this.idNumber = idNumber; }
    public String getName() { return name; }
    public int getIdNumber() { return idNumber; }
    public int compareTo(Object id) { /* some code here */ }
}
一般来说,不使用serialVersionUID并将类转换为接口是一个很难支持的转换

在此特定实例中,我相信您可以通过以下方式支持旧的
Id
实现:

  • 创建一个类(称之为
    OldId
    ),该类具有旧的serialVersionUID和
    Id
    的旧实现(它应该实现
    Id
  • 创建ObjectInputStream的自定义子类并重写
    readClassDescriptor()
    方法。调用父readClassDescriptor并
    • 如果返回的ObjectStreamClass具有
      Id
      类名和旧的serialVersionUID,则为新的
      OldId
      类返回ObjectStreamClass
    • 否则返回给定的描述符

感谢您引导我找到解决方案。我创建了一个
OldId
类,但是重写
resolveClass
无效,因为
ObjectInputStream
抱怨类名与流中声明的类名不匹配。结果我却去了。
java.io.InvalidClassException: mypkg.people.Id; local class incompatible: stream classdesc serialVersionUID = -6494896316839337071, local class serialVersionUID = -869017349143998644
    at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:562)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1583)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1496)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1732)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1947)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1871)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1753)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)
    at mypkg.forms.FormFactory.getForm(FormFactory.java:3115)
    ... 34 more