fastjson低版本反序列化bug/设计缺陷记录
1. 问题场景
_id正常的赋值
相同的代码我们继续跑
_id的值被反序列化到id上了???
相同的代码,跑出不一样的反序列化结果,amazing
2.问题探究
2.1 List<FieldInfo>
反序列化时会先创建一个List<FieldInfo> 每一个FieldInfo List<FieldInfo>的填充方式:遍历Methods[],取出所有的set方法,从set方法里解析字段名并连同对应的set方法构造成一个FieldInfo2.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串里的字段顺序,确得到了更离谱的结果。