FastJSON字段智能匹配踩坑的解决

这篇文章主要介绍了FastJSON字段智能匹配踩坑的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

背景

2021年第一天早上,客户突然投诉说系统的一个功能出了问题,紧急排查后发现后端系统确实出了bug,原因为前端传输的JSON报文,后端反序列化成JavaBean后部分字段的值丢失了。

查看git提交历史记录,前端和后端近期并未对该功能的接口字段做任何修改,联想到上个版本升级了后端的FastJSON的版本,怀疑是后端系统对FastJSON升级导致的问题。

复现

 @Data static class Label { @JSONField(name = "label_id") private Integer labelId; private String labelName; } public static void main(String[] args) { String value = "{'labelId': 1,'label_name':'name'}"; Label label = JSON.parseObject(value, Label.class); System.out.println(label); } 

低版本

  com.alibabafastjson1.2.60

使用低版本FastJSON,如上使用1.2.60版本,示例输出的结果如下,即两个字段JSON解析映射成功。虽然JavaBean中的字段和JSON中的key并不完全匹配(大小写不匹配以及下划线匹配),但得益于FastJSON的智能匹配,忽略了大小写和下划线,依然将JSON映射成功。

 Label(labelId=1, labelName=name)

高版本

  com.alibabafastjson1.2.71

使用高版本FastJSON,如上使用1.2.71,示例输出结果如下,字段labelId映射失败,即高版本FastJSON对智能匹配规则做了修改,并且未向前兼容而导致了部分字段映射失败导致了这次的bug。

 Label(labelId=null, labelName=name)

原理

解析高版本FastJSON字段智能匹配失败的原因,首先要先了解智能匹配的规则。

低版本

低版本的智能匹配规则的关键代码如下,翻译成人话就是:

1、如果JavaBean字段有@JSONField注解且name不空时,则对name的值忽略字母大小写和-,_两个字符

2、否则取JavaBean的字段名,忽略字母大小写和-,_两个字符

3、JSON中的key忽略is开头并忽略剩余字母大小写和-,_两个字符

 // 对JSON中没有成功映射JavaBean的key做智能匹配 // 1. 忽略key的字母大小写和'-','_'两个字符 long smartKeyHash = TypeUtils.fnv1a_64_lower(key); if (this.smartMatchHashArray == null) { long[] hashArray = new long[sortedFieldDeserializers.length]; for (int i = 0; i 

在这里插入图片描述

高版本

高版本的智能匹配规则的关键代码如下,翻译成人话就是:

1、如果JavaBean字段有@JSONField注解且name不空时,则取name的值

2、否则取JavaBean的字段名,忽略字母大小写和-,_两个字符

3、JSON中的key忽略is开头并忽略剩余字母大小写和-,_两个字符

 if (this.smartMatchHashArray == null) { long[] hashArray = new long[sortedFieldDeserializers.length]; for (int i = 0; i 
 // 优先取@JSONField的name字段直接与JSON中的key做匹配 // 其次取JavaBean字段名忽略字母大小写和'-','_'两个字符尝试与JSON中的key做智能匹配 private long nameHashCode64(String name, JSONField annotation) { if (annotation != null && annotation.name().length() != 0) { return TypeUtils.fnv1a_64_extract(name); } return TypeUtils.fnv1a_64_lower(name); } 

在这里插入图片描述

区别

高版本与低版本的智能匹配规则差异就是:如果JavaBean字段有@JSONField注解且name不空时,低配版对name的值会忽略字母大小写和-,_两个字符,而高版本则直接取name的值不会做忽略操作。

因此示例中加了@JSONField注解的labelId字段才会因为FastJSON版本不同而导致反序列化结果的不同。

在对FastJSON的最新几个版本挨个排查后定位出智能匹配规则发生修改的版本为1.2.71,所以如果代码中使用了智能匹配,那么建议谨慎升级到1.2.71及其更高的版本。

另外这么明显的未向前兼容的规则修改,应该有很多人会踩坑。于是去FastJSON的GitHub上查看后果然已经有人提出了issues:1.2.71以上版本加了JSONField的字段无法反序列化

FastJSON解析数据,字段数据不匹配问题

FastJSON中@JSONField注解使用

有个联通的数据要解析出来存入数据库,但是提供过来的json数据有特殊符号'.','-',之前想着直接把特殊的字符给替换掉,解析出来

有一种是可以在实体类上加注解来替换转出来的

fastjson的key是根据javabean里面的getter和setter方法来的,不是根据属性名的,所以会出现这个问题,你在属性的get和set方法上面写上标注,说明转成什么就行了比如 @JSONField(name=”SOMETHING”)

之前想的是替换到json数据里面的特殊字符,然后把实体类的.-都替换掉,这样就可以创建实体类对象了,然后在用fastjson转成对象

后来知道有fastjson的注解的@JSONField(name="name.age-12"来映射上实体类的)

以上为个人经验,希望能给大家一个参考,也希望大家多多支持html中文网。

以上就是FastJSON字段智能匹配踩坑的解决的详细内容,更多请关注0133技术站其它相关文章!

赞(0) 打赏
未经允许不得转载:0133技术站首页 » Java