Java序列化,碰到serialVersionUID不一致怎么处理?

Posted wx5acb795659485

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java序列化,碰到serialVersionUID不一致怎么处理?相关的知识,希望对你有一定的参考价值。

公司有个子服务较多,交互频繁的系统,有一些需要共享传输的对象,它们通过 JDK 序列化(Java Object Serialization)后进行交互;但是由于一些不可描述的历史原因,这些对象存在多个版本,每个版本中的属性不一致,且未设置 ​​serialVersionUID​​。

这阵子在做梳理/统一代码的工作,打算统一这些对象的版本和固定 ​​serialVersionUID​​,但是由于服务较多,上线发版时会有一段新老版本共存的时期,所以得考虑这些对象序列化的兼容问题,新的对象反序列化一定得兼容老的对象。

Java序列化,碰到serialVersionUID不一致怎么处理?_反序列化

Java Object Serialization

Java对象序列化(Serialization)是指将Java中的对象为字节流,从而可以方便的存储或在网络中传输,反序列化(Deserialization)是指将字节流转位Java对象

一般情况下,Java Object Serialization指的是利用JDK自带的功能对对象进行序列化/反序列化,而不是使用其他的序列化库进行(反)序列化

JDK 序列化中,要求对象必须实现​​java.io.Serializable​​接口,基本使用方式如下:

Serialization

// Serialize todays date to a file.FileOutputStream f = new FileOutputStream("tmp");ObjectOutput s = new ObjectOutputStream(f);s.writeObject("Today");s.writeObject(new Date());s.flush();

Deserialization

// Deserialize a string and date from a file.FileInputStream in = new FileInputStream("tmp");ObjectInputStream s = new ObjectInputStream(in);String today = (String)s.readObject();Date date = (Date)s.readObject();

serialVersionUID

private static final long serialVersionUID = 1L;

Java Object Serialization 会使用对象中的 serialVersionUID 常量属性作为该对象的版本号,进行反序列化时会校验该版本号是否一致,如果不一致会导致序列化失败,抛出​​InvalidClassException​​异常

默认情况下,JVM 为每一个实现了 Serializable 的接口的类生成一个 ​​serialVersionUID(long)​​,这个 ID 的计算规则是通过当前类信息(类名、属性等)去生成的,所以当属性有变更时这个serialVersionUID 也一定会发生变更

这个 serialVersionUID 的生成,和所使用的JDK有关,不同的JDK可能会生成不一样的版本号,所以最好是手动生成一个,大多数 JAVA IDE 都会提供这个生成的功能。

Java序列化,碰到serialVersionUID不一致怎么处理?_序列化_02

而且考虑到实际业务场景,变更属性是常有的事,如果使用自动生成的版本号很容易造成 serialVersionUID 不一致的问题,导致反序列化失败

serialVersionUID 不一致兼容处理

处理这个不一致也很简单,既然反序列化时使用 ​​ObjectInputStream​​​ 来实现,那么这里自定义一个 ​​CompatibleInputStream​​​ 继承 ​​ObjectInputStream​​​,然后重写 ​​readClassDescriptor​​ 方法即可

当遇到目标数据 Class 版本号和本地 Class 版本号不一致时,默认使用本地版本的 Class

public class CompatibleInputStream extends ObjectInputStream     private static Logger logger = LoggerFactory.getLogger(CompatibleInputStream.class);    public CompatibleInputStream(InputStream in) throws IOException         super(in);        @Override    protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException         ObjectStreamClass resultClassDescriptor = super.readClassDescriptor(); // initially streams descriptor        Class localClass; // the class in the local JVM that this descriptor represents.        try             localClass = Class.forName(resultClassDescriptor.getName());          catch (ClassNotFoundException e)             logger.error("No local class for " + resultClassDescriptor.getName(), e);            return resultClassDescriptor;                ObjectStreamClass localClassDescriptor = ObjectStreamClass.lookup(localClass);        if (localClassDescriptor != null)  // only if class implements serializable            final long localSUID = localClassDescriptor.getSerialVersionUID();            final long streamSUID = resultClassDescriptor.getSerialVersionUID();            if (streamSUID != localSUID)  // check for serialVersionUID mismatch.                final StringBuffer s = new StringBuffer("Overriding serialized class version mismatch: ");                s.append("local serialVersionUID = ").append(localSUID);                s.append(" stream serialVersionUID = ").append(streamSUID);                Exception e = new InvalidClassException(s.toString());                logger.error("Potentially Fatal Deserialization Operation.", e);                resultClassDescriptor = localClassDescriptor; // Use local class descriptor for deserialization                            return resultClassDescriptor;    

Java序列化,碰到serialVersionUID不一致怎么处理?_序列化_03

使用方式:

// Deserialize a string and date from a file.FileInputStream in = new FileInputStream("tmp");//反序列化时使用上面的CompatibleInputStream即可ObjectInputStream s = new CompatibleInputStream(in);String today = (String)s.readObject();Date date = (Date)s.readObject();


Java序列化,碰到serialVersionUID不一致怎么处理?_java_04

以上是关于Java序列化,碰到serialVersionUID不一致怎么处理?的主要内容,如果未能解决你的问题,请参考以下文章

浅谈Java中JSON的序列化问题

Java中的transient关键字

java----八种排序算法

8 种排序算法与 Java 代码实现!

反序列化漏洞复现总结

java----八种排序算法