fastjson低版本反序列化bug/设计缺陷记录

1. 问题场景

 _id正常的赋值

相同的代码我们继续跑

 _id的值被反序列化到id上了???

相同的代码,跑出不一样的反序列化结果,amazing

2.问题探究

2.1 List<FieldInfo>

反序列化时会先创建一个List<FieldInfo>

每一个FieldInfo

List<FieldInfo>的填充方式:遍历Methods[],取出所有的set方法,从set方法里解析字段名并连同对应的set方法构造成一个FieldInfo

 2.2 List<FieldInfo>覆盖问题

构造好FieldInfo后添加到列表的方式

可以看到如果后加进来的FieldInfo满足:①name跟列表里某个存在的FieldInfo.name一致 ②.class类型一致;那么后面加进来的FieldInfo会覆盖掉之前的FieldInfo

回到生成FieldInfo这一步,深入研究name字段赋值逻辑

 

2.3 propertyName (FieldInfo.name)取值方式

 可以看出来,在java代码中

字段_id,其set方法名为set_id(),那么此处得到的propertyName为id;

字段id,其set方法名为setId(),那么此处得到的propertyName也为id;

2.4 初步结论

由于2.2中提到的覆盖和2.3中不同字段取成了相同的propertyName(FieldInfo.name),所以其实最后的List<FieldInfo>中只有一条数据

name = id,method = setId() 或者 name = id,method = set_id()

至于到底是哪一条

 取决于clazz.getMethods()出的Method[]里的set_id()和setId()的顺序,这个顺序在类信息加载进堆内的时候定死了,但是如果 重新启动的话,就会重新排序,所以反序列化时赋值到_id还是id上是在掷骰子。。。

 

 可以看到如果类信息装载一次,的话由于Method[]固定,反序列化受到赋值的字段也是固定的。

3. 问题解决

在set方法上使用JSONField(name=“”)手动指定propertyName,避免List<FieldInfo>存在的覆盖问题

 

4. 更多的bug

fastjson的反序列化其实总体可以分为三步

①解析要赋值的字段名 propertyName

②得到调用的的赋值方法

③从json串里获取待赋的值

我们刚才其实找到了①和②存在一些设计缺陷

但其实③的取值好像也有些奇怪的问题

 可以看到我们仅仅是把json串从{"_id":"aaa","id":null}变为{"id":null,"_id":"aaa"} ,变更了json串里的字段顺序,确得到了更离谱的结果。

posted @ 2024-07-02 14:51  忙碌了一整天的L师傅  阅读(38)  评论(0编辑  收藏  举报