【问题标题】:Java backward-compatibility: how readObject() read same classname objects with different serialVersionUID?Java 向后兼容性:readObject() 如何读取具有不同 serialVersionUID 的相同类名对象?
【发布时间】:2017-04-19 13:17:59
【问题描述】:

此套接字将继续接收一些旧对象和新对象 一样的名字。但是,如果我直接使用 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 本地类不兼容:流 classdesc serialVersionUID = 1,本地类 serialVersionUID = 2

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

谢谢。

【问题讨论】:

  • “它们完全一样” - 不,根据您的评论,它们位于不同的包中。完全限定的类名在序列化(和一般情况下)中很重要。
  • 您是在问如何将一个类的序列化对象作为另一个类的实例读取?
  • 它们是两种不同的类型。序列版 UID 与它无关。投射到HashMap 并阅读其条目。
  • @qxz 是的。我只想读取这些数据。
  • 你确定类的serialVersionUID 在你序列化对象后没有改变吗?这就是您的例外所建议的。

标签: java backwards-compatibility serialversionuid


【解决方案1】:

Java:readObject() 如何读取具有不同serialVersionUID 的两个类?

很容易。他们是不同的班级。为什么不应该呢?

有两个同名但serialVersionUID不同的类。

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

我遇到了这个致命的异常:

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

这与不同包中具有相同名称的两个类没有任何关系。这意味着您在发送方部署了该类的一个版本,serialVersionUID = 2,在接收方部署了另一个版本,serialVersionUID = 1。解决方案:不要那样做。部署相同的版本:在这种情况下,带有2 的版本,因为这就是流中的内容。一般来说,您应该不在不知道确切您在做什么的情况下更改serialVersionUID 的值。

就我而言,有两个版本的类发送到我身边。 1L 和 2L。

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

【讨论】:

    【解决方案2】:

    只要我们扩展 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)

    【讨论】:

      猜你喜欢
      • 2018-09-01
      • 2016-01-04
      • 2015-02-07
      • 1970-01-01
      • 2019-09-09
      • 2022-09-27
      • 1970-01-01
      • 2013-08-13
      • 2020-06-10
      相关资源
      最近更新 更多