004-protostuff踩坑-java bean新增字段反序列化失败问题
protostuff 避免 更改 java 对象字段 ,比如新增一个,导致 redis 等缓存 的数据反序列化失败问题??
问题重现:
我们有个方法 通过 attrKey 查询 List ,同时方法中有缓存,会优先查询缓存,没有读库,然后 写缓存 返回。
方法伪代码如下:
public ConfAttr getConf(String attrKey) {// 从 缓存查询List<ConfAttr> attrValues = cacheClient.get(attrKey);if(attrValues !=null && !attrValues.isEmpty(){return attrValues.get(0);}// 读库List<ConfAttr> attrValues = selectFromDb(attrKey);cacheClient.put(attrKey,attrValues, cacheSeconds);return attrValues.get(0);
}
然后某天业务迭代 ConfAttr类增加 source 属性。上线后 redis 反序列化出错。错误内容如下:
Exception in thread "main" java.lang.RuntimeException: Reading from a byte array threw an IOException (should never happen).at io.protostuff.IOUtil.mergeFrom(IOUtil.java:54)at io.protostuff.ProtostuffIOUtil.mergeFrom(ProtostuffIOUtil.java:104)at com.cm.cache.serialize.ProtostuffSerializer.deserialize(ProtostuffSerializer.java:34)at com.cm.cache.redis.ShardedRedisClient.get(ShardedRedisClient.java:88)at com.test.RedisTest.main(RedisTest.java:51)
Caused by: io.protostuff.ProtobufException: CodedInput encountered an embedded string or bytes that misreported its size.at io.protostuff.ProtobufException.misreportedSize(ProtobufException.java:86)at io.protostuff.ByteArrayInput.readString(ByteArrayInput.java:438)at io.protostuff.runtime.RuntimeUnsafeFieldFactory$9$1.mergeFrom(RuntimeUnsafeFieldFactory.java:753)at io.protostuff.runtime.RuntimeSchema.mergeFrom(RuntimeSchema.java:466)at io.protostuff.runtime.ObjectSchema.readObjectFrom(ObjectSchema.java:693)at io.protostuff.runtime.IdStrategy$8.mergeFrom(IdStrategy.java:503)at io.protostuff.ByteArrayInput.mergeObjectEncodedAsGroup(ByteArrayInput.java:518)at io.protostuff.ByteArrayInput.mergeObject(ByteArrayInput.java:490)at io.protostuff.runtime.IdStrategy$10.mergeFrom(IdStrategy.java:583)at io.protostuff.runtime.IdStrategy$10.mergeFrom(IdStrategy.java:528)at io.protostuff.runtime.ObjectSchema.readObjectFrom(ObjectSchema.java:590)at io.protostuff.runtime.ObjectSchema.mergeFrom(ObjectSchema.java:350)at io.protostuff.ByteArrayInput.mergeObjectEncodedAsGroup(ByteArrayInput.java:518)at io.protostuff.ByteArrayInput.mergeObject(ByteArrayInput.java:490)at io.protostuff.runtime.RuntimeUnsafeFieldFactory$15$1.mergeFrom(RuntimeUnsafeFieldFactory.java:1217)at io.protostuff.runtime.RuntimeSchema.mergeFrom(RuntimeSchema.java:466)at io.protostuff.IOUtil.mergeFrom(IOUtil.java:45)... 4 more
问题答案
正确答案1:
可以使用@Tag 注解 指定字段顺序。
错误答案1:
将新增的字段加载java bean 类 的末尾 就可以避免该问题了(但是实际上这种还是存在错误的可能 ,具体参考 下一节的原理分析),
PS: 这次出问题 是因为 把sourceid 加入到 属性定义的中间了。
基于错误答案1的尝试截图
改动前:
改动后:
知识点拓展 protostuff 按照什么顺序来给类的 字段 序列化呢?
说明
- protostuff 只序列话字段值,不序列化 key(map可能除外)
- 顺序默认按照 typeClass.getDeclaredFields() (但是 jdk的这个方法 返回顺序,不是按照源码 的字段申明顺序,可能会被jdk 重编译 而改变顺序,大部分时候是按照申明的顺序)
- 所以 有时候添加字段,如果加载类 字段申明的末尾,不会出问题,加在中间,反序列化就会出问题。
- 不能依赖于 typeClass.getDeclaredFields(), 强制要求 按照 @Tag 添加指定字段顺序。(参考 https://houbb.github.io/2018/07/01/reflection-12-fields)
- protostuff 根据 getDeclaredFields 获取字段列表:会忽略 static transient 以及用注解@Exclude 。
方法入口
入口
io.protostuff.runtime.RuntimeSchema#fill
static void fill(Map<String, java.lang.reflect.Field> fieldMap,Class<?> typeClass)
{if (Object.class != typeClass.getSuperclass())fill(fieldMap, typeClass.getSuperclass());for (java.lang.reflect.Field f : typeClass.getDeclaredFields()){int mod = f.getModifiers();if (!Modifier.isStatic(mod) && !Modifier.isTransient(mod) && f.getAnnotation(Exclude.class) == null)fieldMap.put(f.getName(), f);}
}
调用图
004-protostuff踩坑-java bean新增字段反序列化失败问题相关推荐
- Java bean中字段命名潜规则,前两个字母要么都大写,要么都小写
Java bean中字段命名潜规则,前两个字母要么都大写,要么都小写,否则会出错 以下代码是获取字段名的源码,根据这段代码可以得知: 输入 输出 AA AA A ...
- #Jetson-NX踩坑记--Etcher Flash Failed 烧录失败的解决办法
#Jetson-NX踩坑记--Etcher Flash Failed 烧录失败的解决办法 问题 解决方案 问题 根据 官方教程 使用 Etcher 烧录 Jetson NX 的镜像文件时总是失败,如图 ...
- Vue 踩坑笔记: 引入 ElementUI 时打包失败修复记录(ERROR in ./node_modules/element-ui/lib/theme-chalk/index.css)
Vue 踩坑笔记: 引入 ElementUI 时打包失败修复记录(ERROR in ./node_modules/element-ui/lib/theme-chalk/index.css Module ...
- #踩坑 Java 使用itextpdf将PDF模板导出文件过大
itextpdf导出文件 踩坑 问题产生 解决方案 最终方法 涉及到的公共方法/参数 问题产生 处理需求将PDF模板导出后发现前端调取文件时间过长,1min左右.查看才发现导出的文件6m左右,又查看了 ...
- java split 坑_java String split 踩坑记
split操作是出镜率非常高的一个方法, 但是我们使用中通常会使用两个类提供的split方法, 他们在入参类型一样, 但是效果却有一些差别, 稍不注意容易踩坑. java.lang.String#sp ...
- mybatis学习与踩坑记录
mybatis resultmap高级映射 应用场景:如果sql查询的列名和pojo的属性名不一致,可以使用resultMap将列名和pojo的属性名作一个对应关系,就可以映射成功了.(如果返回值为i ...
- 安装sql server踩坑记【sql2000程序安装配置服务器失败】
安装sql server踩坑记 安装程序配置服务器失败.参考服务器错误日志和 C:\WINDOWS\sqlstp.log 了解更多信息. 在C:\Program Files\Microsoft SQL ...
- 测试踩坑 - 当已有接口(或数据库表中)新增字段时,都需要注意哪些测试点?
最新在测试的时候,遇到了几个典型问题,都是在原有接口(或数据库表中)进行需求迭代时,出现的问题.我稍微总结一下,作为后续测试的经验教训. 问题一.数据库表中新增字段,但开发将这几个字段设置成了非空字段 ...
- 开发|MySQL新增字段踩坑
提醒一下自己!!!! 在开发的过程中!!一些上线的项目,有一定人数日常使用的项目,不要在日常时段进行一些大数据量的表的新增字段(比如用户表)!!!!! 会卡死,只能重启数据库
最新文章
- 超人类AI的幻想与思考:自下而上构建的自我迭代意识系统
- 解析时代需要什么样的根目录,中国科技需要什么样的根技术
- freebsd 同步工具unison
- python---基础知识回顾(十)进程和线程(协程gevent:线程在I/O请求上的优化)...
- java的JDK配置
- python后端教程_Python学习教程(技术干货):关于前后端分离开发入门
- Create a virtualbox Based CentOS 6 OpenStack Cloud Image
- 转-----EasyCHM制作教程
- 矩阵乘法,输出结果矩阵
- 电路串联和并联图解_串联电路与并联电路的区别
- 小和尚打水问题_操作系统进程同步问题解析(哲学家问题、生产消费问题、小和尚打水问题等大量例子)...
- 为什么现在的程序员那么卑微?青出于蓝而胜于蓝啊
- Codeforces Problem-1591B Array Eversion
- 心得体会标题大全_给心得起个标题
- Vue开发之基础路由
- DDR扫盲——DDR与DDR2、DDR3的区别
- 亚马逊测评的获得方法及测评环境系统介绍,一次诊断全部解决。
- Cont. TF-IDF (BigData Data Mining)
- 爬虫系列(四)--全站爬取
- Xilinx FPGA PCIe XDMA性能测试报告(一)
热门文章
- 有出租高性能服务器的么,租用高性能的美国服务器有怎样配置呢?
- 服务器系统安装提示无法创建新的系统分区,安装win10系统提示“我们无法创建新的分区,也找不到现在的分区”如何解决...
- 机器学习--过度拟合 欠拟合
- jsqlparser mysql_使用JSQLParser解析SQL中涉及到的表
- 带你了解什么是Thymeleaf(实操)
- 从高中到大学 寻找真实的自己
- 休学的影响来了,家长多养孩子一年
- CE修改模拟器里的数据
- Java中的String,StringBuffer,StringBuilder有什么区别?
- Python学习笔记——用户登录测试