fastjson设计缺陷

1.com.alibaba.fastjson.util.TypeUtils.computeGetters方法
/关闭ASM模式
SerializeConfig config= new SerializeConfig();
config.setAsmEnable(false);
JSON.toJSONString(list,config);

存储从对象提取的属性string的对象

bug调试路径

 

 

下面这个地方是真正赋值的地方 

 

 下面是有设计缺陷的方法

这个方法的主要功能是,如果关闭了ASM,在对象转JSON字符串的时候,属性名是通class的get方法名获取的

循环遍历方法时过滤得到的get方法会用来提取属性名

下面带着实例看方法走向,如果现在有个属性是String ID---这种命名我相信大家都能接受吧,不算奇怪

那么使用Lombok默认的get方法是getID()---当然我相信自己写也是这个名字

下面这方法会走if(Character.idUpperCase(c3))这条,然后会根据是否开启了兼容模式(默认不开启)进两个分支

 首先是第一个分支(开启兼容模式)

propertyName = decapitalize(methodName.substring(3));

可以看到方法内部会走第二哥return返回,即如果get方法后续的属性后缀的前两个字符都是大写,就直接返回

最后propertyName为ID---解析正确

第二个分支(默认不开兼容模式)

propertyName = TypeUtils.getPropertyNameByMethodName(methodName);

结果为iD---属性名解析错误!!!

 这个时候聪明的朋友就会说了,那人就是这么设计的这种解析规则,你自己不开兼容模式怪谁?

没毛病!那么你接着看

 毫无疑问getID()还符合

 可以看到这个if分支是直接采用前面的兼容模式下的方法解析的,而这个分支的匹配条件get后缀的属性字段长度>=2,并且第二个字符是大写,然后进方法后再判断第一个字母是不是大写,是的话就直接保留原名称

 

问题所在:

但是这两个分支产生了部分的匹配重合---当属性长度大于1,且开头两个字母都是大写时(这种情况很常见,比如各种特殊缩写CCTV,CNN,BBC),且没有开启兼容模式的情况下,本来应该走decapitalize方法保留原名称,但是却走到了TypeUtils.getPropertyNameByMethodName把首字母小写了,原因其实就是匹配的先后顺序,开发人员在处理开头字母是大写的属性和开头两个字母都是大写的属性时代码逻辑产生了矛盾

 

吐槽:

使用get方法提取对应的属性名称(这种做法我感觉有点奇怪)

为什么对象转JSON字符串的时候要通过反射去get方法名中提取属性???

既然用了反射为什么不直接拿class的field,而舍近求远的去get方法名中提取,导致写那么多提取规则还不准确

 

 所有经过处理的propertyName存到fieldInfoMap里面,后续用作json字符串生成

posted @ 2022-09-21 18:32  忙碌了一整天的L师傅  阅读(236)  评论(0编辑  收藏  举报