【问题标题】:Finding serialVersionUID of serialized object查找序列化对象的serialVersionUID
【发布时间】:2010-11-22 06:15:47
【问题描述】:

有没有办法确定序列化Java对象生成的@​​987654321@?

问题是我序列化了一个对象而没有明确指定serialVersionUID。现在反序列化过程抱怨类不兼容。但是,我没有以使其不兼容的方式更改课程。所以我假设在类中指定serialVersionUID 就足够了,因为它存储在对象数据中。为此,我需要从序列化数据中读取serialVersionUID

【问题讨论】:

  • 在类中添加方法时会发生什么情况?可以使用修改后的序列化类读取旧的序列化对象吗?
  • 方法不构成对象的状态,所以读取序列化对象没有问题,除非你没有使用任何serialVersionUID..

标签: java serialization serialversionuid


【解决方案1】:

这对我有用:

long serialVersionUID = ObjectStreamClass.lookup(YourObject.getClass()).getSerialVersionUID();

希望对你也有帮助。

【讨论】:

    【解决方案2】:

    有一种简单的方法可以找出类的serialversionUID-

    假设你有一个类,你忘记提到serialversionUID-

    import java.io.Serializable;
    
    public class TestSerializable implements Serializable {
    
    }
    

    就这么做-

    serialver -classpath . TestSerializable
    

    这打印-

    static final long serialVersionUID = 5832063776451490808L;
    

    serialver 是 JDK 自带的实用程序

    【讨论】:

    • 但这只有在你有旧版本的 TestSerializable 类时才有效。 lewap 的问题是他不知道 serialVersionUID 的值与他序列化的对象的旧版本的类有关。如果他不再需要旧版本的课程,他就无法使用serialver来查找。
    • 这就是版本控制的用途。
    • 很好的答案,但如果类导入框架类型(如上下文),它就不适用于 Android
    【解决方案3】:

    你可以通过扩展ObjectInputStream来做到这一点:

    public class PrintUIDs extends ObjectInputStream {
    
      public PrintUIDs(InputStream in) throws IOException {
        super(in);
      }
    
      @Override
      protected ObjectStreamClass readClassDescriptor() throws IOException,
          ClassNotFoundException {
        ObjectStreamClass descriptor = super.readClassDescriptor();
        System.out.println("name=" + descriptor.getName());
        System.out.println("serialVersionUID=" + descriptor.getSerialVersionUID());
        return descriptor;
      }
    
      public static void main(String[] args) throws IOException,
          ClassNotFoundException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        List<Object> list = Arrays.asList((Object) new Date(), UUID.randomUUID());
        oos.writeObject(list);
        oos.close();
        InputStream in = new ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream ois = new PrintUIDs(in);
        ois.readObject();
      }
    
    }
    

    我相信可以通过替换方法返回的描述符来读取所有的序列化数据,但是我没有尝试过。

    【讨论】:

      【解决方案4】:

      有与序列化位相关的元数据(如果您愿意,可以使用标头)。如果您知道它在哪个位置,则可以从元数据中读取该值(SerialVersionUID 与其他信息(例如类名)一起写在那里)。

      我认为这篇文章可能会对您有所帮助:The Java serialization algorithm revealed

      请注意,这些位是“以明文形式”写入的(除非您明确加密了流),因此您可能只需要一个 HEX 编辑器就可以查看SerialVersionUID 是什么。

      【讨论】:

        【解决方案5】:

        对象的序列化有指定的语法:

        参见第 6.4 节 http://java.sun.com/javase/6/docs/platform/serialization/spec/serialTOC.html

        使用它,您应该能够确定序列化对象的 SerialVersionUID。

        【讨论】:

          【解决方案6】:

          对于 Android 开发者,

          您也可以从 Settings -> Editor -> Inspections -> 先启用“Serializable class without 'serialVersionUID' check”启用序列化检查,然后按 ALT+ ENTER,工作室将为您创建 serialVersionUID。

          【讨论】:

            【解决方案7】:

            这正是你应该做的——指定你自己的static final long serialVersionUID

            Serializable 的文档中有一个关于它的部分。

            除非您指定了 serialVersionUID,否则我认为除了按照 @WMR 的建议破译流之外,没有其他简单的方法可以获取它。

            【讨论】:

            • 注意它应该命名为serialVersionUID(不是:serialversionuid - Java区分大小写),它应该是private static final long)。
            • 我同意。但是有没有办法从序列化数据中读取生成的uid?
            【解决方案8】:

            有更简单的方法来获取序列化对象的 serialVersionUID - 只需使用 apache commons 序列化工具将其反序列化为具有不同序列版本 uid 的同一类并读取或多或少的异常消息:

            org.apache.commons.lang.SerializationException: java.io.InvalidClassException: my.example.SerializableClass;本地类不兼容:stream classdesc serialVersionUID = -1,本地类serialVersionUID = -2

            【讨论】:

              【解决方案9】:

              获取它的最简单方法(尤其是在很难找到的情况下)是为 serialVersionUID 定义任意数字并在反序列化失败时监视堆栈跟踪,它将打印出原始的。

              【讨论】:

                猜你喜欢
                • 2017-07-29
                • 1970-01-01
                • 1970-01-01
                • 2010-10-01
                • 2013-01-21
                • 1970-01-01
                • 2015-04-21
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多