Java 向后兼容性:readObject() 如何读取具有不同 serialVersionUID 的相同类名对象?

Java backward-compatibility: how readObject() read same classname objects with different serialVersionUID?

这个套接字将继续接收一些旧对象和新对象 一样的名字。但是,如果我直接使用 readObject,它会抛出 致命异常。我们中的一些人会建议忽略旧对象或 更改旧的目标代码。这对我来说是不可能改变的 客户端代码。我需要处理 向后兼容性


Socket s = ss.accept();
ObjectInputStream lvStream = new ObjectInputStream(s.getInputStream());
Object lvObject = lvStream.readObject();

// The old class but released ( I cannot change it )
public class Apple extends HashMap<String, String> {
    private static final long serialVersionUID = 1L;
}
// The old class but released ( I cannot change it )
public class Apple extends HashMap<String, String> {
    private static final long serialVersionUID = 2L;
}

// The new class in my local ( 1L or 2L still would not solve the issue easily )
public class Apple extends HashMap<String, String> {
    private static final long serialVersionUID = 2L;
}

在readObject()的那一行, 我遇到了这个致命异常:

java.io.InvalidClassException 本地 class 不兼容:流 classdesc serialVersionUID = 1,本地 class serialVersionUID = 2

如何读取这两种 Apple 对象数据(Hashmap)?

谢谢。

Java: how can readObject() read two classes with different serialVersionUID?

很容易。它们是不同的 classes。为什么不呢?

There are two class with same name but different in serialVersionUID.

所以它们是不同的class。你的问题?

I got this fatal exception:

java.io.InvalidClassException local class incompatible : stream classdesc serialVersionUID = 2, local class serialVersionUID = 1

这与在不同包中具有相同名称的两个 class 没有任何关系。这意味着您在发送方部署了 class 的 serialVersionUID = 2 版本,而在接收方部署了 serialVersionUID = 1 的不同版本。苏蒂安:不要那样做。部署相同的版本:在本例中,带有 2 的版本,因为它是流中的版本。一般而言,您应该在不知道确切您在做什么的情况下更改serialVersionUID值。

In my case, there are two versions class sending to my side. 1L and 2L.

不,没有。有一个发送版本,2L,和一个不同版本的接收,1L。不要那样做。

只要我们扩展ObjectInputStream,

我们将有权访问流 SerialVersionUID 以与本地 SerialVersionUID 进行比较。


Socket s = ss.accept();
// use the extended ObjectInputStream ( DecompressibleInputStream )
DecompressibleInputStreamlvStream = new DecompressibleInputStream(s.getInputStream());
Object lvObject = lvStream.readObject();

import java.io.IOException;
import java.io.InputStream;
import java.io.InvalidClassException;
import java.io.ObjectInputStream;
import java.io.ObjectStreamClass;

public class DecompressibleInputStream extends ObjectInputStream {

    public DecompressibleInputStream(InputStream in) throws IOException {
        super(in);
    }

    protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException {
        ObjectStreamClass resultClassDescriptor = super.readClassDescriptor();
        Class<?> localClass;
        try {
            localClass = Class.forName(resultClassDescriptor.getName()); 
        } catch (ClassNotFoundException e) {
            System.err.println("No local class for " + resultClassDescriptor.getName());
            return resultClassDescriptor;
        }
        ObjectStreamClass localClassDescriptor = ObjectStreamClass.lookup(localClass);
        if (localClassDescriptor != null) {
            final long localSUID = localClassDescriptor.getSerialVersionUID();
            final long streamSUID = resultClassDescriptor.getSerialVersionUID();
            if (streamSUID != localSUID) {
                System.err.println("Potentially Fatal Deserialization Operation.");
                resultClassDescriptor = localClassDescriptor;
            }
        }
        return resultClassDescriptor;
    }
}

希望对您有所帮助

(感谢此 post