Java-序列化serialVersionUID不一致处理_java序列化时对象属性不一致报错怎么办-程序员宅基地

技术标签: java  源码  

背景

Java Object Serialization 会使用对象中的serialVersionUID私有静态常量长整型属性(private static final long)作为该对象的版本号,反序列化时 JVM 会校验该版本号是否和序列化时的一致,如果不一致会导致序列化失败,抛出InvalidClassException异常。

截图

默认情况下,JVM 为每一个实现了Serializable的接口的类生成一个serialVersionUID,这个版本ID的计算规则是通过当前类信息(类名、属性、方法、修饰符等)生成的,所以当属性有变更时这个serialVersionUID也一定会发生变更(简单新增空行、空格并不会影响serialVersionUID生成)。

这个serialVersionUID的生成,和所使用的JDK有关,不同的JDK可能会生成不一样的版本ID。

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

所以最好是手动显示生成,大多数 JAVA IDE 都会提供自动生成版本ID的功能。

serialVersionUID不一致的兼容处理

普通序列化(Serialization) 和 反序列化(Deserialization):

public class SerializeTest {
    

    public static void main(String[] args) throws Exception {
    
        // Serialize to a file.
        FileOutputStream f = new FileOutputStream("./tmp");
        ObjectOutput s = new ObjectOutputStream(f);
        s.writeObject("Today");
        s.writeObject(new Person());
        s.flush();

        // Deserialize a string and object from a file.
        FileInputStream in = new FileInputStream("./tmp");
        ObjectInputStream rd = new ObjectInputStream(in);
        System.out.println((String) rd.readObject());
        System.out.println((Person) rd.readObject());
    }
}

使用ObjectOutputStream序列化到文件中,然后使用ObjectInputStream反序列化,这种方式,如果serialVersionUID不一致反序列化时会报错;

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

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

public class CompatibleInputStream extends ObjectInputStream {
    
    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) {
    
            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);
                System.out.println(s);
                resultClassDescriptor = localClassDescriptor; // Use local class descriptor for deserialization
            }
        }
        return resultClassDescriptor;
    }
}

测试:

public class SerializeTest {
    

    public static void main(String[] args) throws Exception {
    
        // Deserialize a string and object from a file with CompatibleInputStream.
        FileInputStream in = new FileInputStream("./tmp");
        CompatibleInputStream rd = new CompatibleInputStream(in);
        System.out.println((String) rd.readObject());
        System.out.println((Person) rd.readObject());
    }
}

结果:

Today
Overriding serialized class version mismatch: local serialVersionUID = 3 stream serialVersionUID = 514127872132381055
com.wkw.study.jdk.serialize.Person@41cf53f9

参考:

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

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/FromZeroJiYuan/article/details/121463453

智能推荐

SLS 智能告警平台最新技术总结_数据中台 告警系统-程序员宅基地

文章浏览阅读1.6k次。本文主要讲述过去一年内可观测平台 SLS 的改进和迭代。_数据中台 告警系统

win7 系统装SQLServer2000 成功_ghost封装sql 2000-程序员宅基地

文章浏览阅读854次。昨天在win7上装SQLServer数据库,写一下体会。首先,如果以前安装的话,要删除干净。我也找了半天的网络资料。1.把原来SQLServer的安装目录 C:\Program Files\Microsoft SQL Server 删除2.所有SQLServer相关的注册表全部删除,保证系统是没有装过SQLServer的状态注册表打开方式:开始-->运行-->rege_ghost封装sql 2000

关于ViewPager设置属性页setCurrentItem会阻塞主线程ANR总结-程序员宅基地

文章浏览阅读235次。关于android开发设置View Pager的直接跳转页set CurrentItem会阻塞主线程ANR。根据网上解决的说法,分析源码:if (mFirstLayout) { // We don't have any idea how big we are yet and shouldn't have any pages either. // Just..._viewpager#mfirstlayout

Windows下Nginx负载均衡配置和优化方案_windows nginx优化-程序员宅基地

文章浏览阅读1.1k次。Windows下Nginx负载均衡配置和优化方案方案配置的环境:安装环境:Windows系统Nginx版本:nginx-1.18.0代理网站服务器:Windows server系统1.Nginx下载进入下载地址:http://nginx.org/en/download.html选择Windows版本进行下载。2.Nginx安装2.1解压安装将下载好的Nginx压缩文件解压在相关的安装位置,建议放在非C盘的根目录下,原因是网站访问量大时,产生的日志容量会很大,从而占据C盘的存储空间,增加_windows nginx优化

小程序滚动切换页码组件_wux-refresher loadmore-程序员宅基地

文章浏览阅读640次。以下是基于小程序wux框架中refresh组件拓展的小程序滚动切换页码组件。用法<page-list id="wux-refresher" elid="biddingList" isShowPage="{{false}}" bind:scrollbot="scrollbot" bind:refresh="onRefresh"> <template is="b..._wux-refresher loadmore

oracle 断电启动失败:ORA-00600: internal error code, arguments_ora-00600: internal error code, arguments: [kgepop-程序员宅基地

文章浏览阅读2.3k次。由于服务器断电,启动 oracle 时报 ORA-00600 错误查看 oracle trace 日志1. 执行 sqlplus 登录 oraclesqlplus / as sysdba1.2 启动,报错信息如下SQL> startupORACLE instance started.Total System Global Area 583008256 bytesFix_ora-00600: internal error code, arguments: [kgepop: no error frame to pop to

随便推点

用sqoop将hive导入mysql中文乱码_sqoop --default-character-set=utf8-程序员宅基地

文章浏览阅读1.5k次。修改/etc/my.cnfcharacter-set-server=utf8[client]default-character-set=utf8注释掉 sql_mode重新新建mysql表在hive的元数据库中执行以下SQL语句,然后重新创建刚才的表即可 。alter table COLUMNS_V2 modify column COMMENT varchar(256) character set utf8;alter table TABLE_PARAMS modify column PAR_sqoop --default-character-set=utf8

python中将xml格式转json格式-程序员宅基地

文章浏览阅读845次。一、简介 在用python写脚本时,通常需要处理xml格式的文件或字符串。由于json格式处理的方便性, 我们可将其转为json格式进行处理。 二、步骤 1、安装工具包xmltodict 在命令行输入:pip install xmltodict 2、在代码使用xmltodict.parse(xml_str)进行处理 如 def load_json(xml_path): #获取xml文件 xml_f..._python xml 转json 格式

用了smarty两年多,才知道在模板中可以直接调用PHP内置函数_smarty中的内置函数可以实现邮件链接的是-程序员宅基地

文章浏览阅读661次。比如说:模板书写:{'param1'|functionName:'param2':'param3'}php函数原型:echo functionName('param1','param2','param3');实例:{'1234567'|substr_smarty中的内置函数可以实现邮件链接的是

深度学习笔记~集成方法bagging, boosting和stacking_bagging方法结合深度学习模型-程序员宅基地

文章浏览阅读2.4k次。转载:https://towardsdatascience.com/ensemble-methods-bagging-boosting-and-stacking-c9214a10a205作者:Joseph Rocca Ensemble methods: bagging, boosting andstackingIntroduction“Unity is ..._bagging方法结合深度学习模型

java 开发 文件夹创建和删除_文件的创建和删除java-程序员宅基地

文章浏览阅读6.7k次。//返回文件名称(文件夹读取文件)public static ArrayList<String> getFilesPath(String path) throws Exception {//目标集合fileListArrayList<String> fileList = new ArrayList<String>();File file = new ..._文件的创建和删除java

推荐文章

热门文章

相关标签