前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >记一次 FastJson 的踩坑经历

记一次 FastJson 的踩坑经历

作者头像
南风
发布2020-02-17 12:46:25
1.2K0
发布2020-02-17 12:46:25
举报
文章被收录于专栏:Java大联盟Java大联盟

项目和第三方对接,有接口一直调不通,直到我拿到合作方的入参后,问题来了,有了接下来的一系列故事。

拿到原生的第三方参数( JSON 格式的),为了节省时间,迫不及待地直接在本地单元测试一波。熟悉的操作,这里为了方便观察,我模拟一次请求从 Controller 进入的请求:

代码语言:javascript
复制
import com.alibaba.fastjson.JSON;import lombok.Data;

public class ProFastjson {
    @Data
    static class Teacher {
        private String teacherName;
    }

    private static TeacherController teacherController = new TeacherController();

    public static void main(String[] args) {
        String str = "{\"teacher_name\":\"zxerjones\"}";
        Teacher teacher = JSON.parseObject(str, Teacher.class);
        teacherController.search(teacher);
    }
}

看重点:我的 JSONString 参数名有下划线,Teacher 的是没有 teacher_name 这个属性的,反序列化之后的值应该是空的,可偏偏方法走通了。不甘心的我决定 debug 一波,如下图:

反序列化结果

反序列化成功了,是不是一脸懵逼。没错 FASTJson 就是不和你讲道理。行吧,那一定是是 FASTJson 内部的反序列化机制造成这样的结果,debug 进源码看看:

JSON.parseObject 方法内部

注意看上图 378 行,JSON 的反序列化就是在这个方法中实现的,继续跟进:

DefaultJSONParser.parseObject 方法内部

上图对一些规则进行校验之后,开始进入主题。正式调用反序列化工具 JavaBeanDeserializer.deserialze 对字符进行反序列化。这个方法主要做的事情就是对 JSON 字符串内部的键值对和我们需要的反序列化结果类进行绑定,赋值(这个方法代码比较多,只贴重点):下图是赋值的过程,这才是导致问题的关键:

JavaBeanDeserializer.deserialze 方法内部

就是 850 行代码,终于找到问题的所在了,马上就真相大白。现在可以确定就是 parseField 方法搞的鬼,继续点进去:

parseField 方法内部

上图方法内部做的事情就是生成 field 反序列化工具对 field 反序列化,然后赋值。这个 field 反序列化工具从何而来断点打到 1089 行,可以看到,这个方法返回了我们需要的工具,点进去:

JavaBeanDeserializer.smartMatch 方法内部

代码做的事情就是根据 JSON 字符串的键(teacher_name)做一次 hash 运算,然后与需要反序列化结果(Teacher.class)中的所有参数(这里只有teacherName)做 hash 运算,根据生成的 hash 值来对 field 进行配对。OK就是这样的,现在我们已经找到问题的根源,hash 之后的值是相同的。fastjosn 内部封装了计算 hash 的工具类,TypeUtils.fnv1a_64_lower,如下图:

TypeUtils.fnv1a_64_lower

代码中可以看到进行hash的两个规则:

1、‘-’和‘_’不参与hash运算。

2、忽略大小写。

根据最后得出的 hash 规则,那么可以在 json 字符串中随意的添加"_","-",并且大小写忽略都可以反序列化成功,证实下猜想:如下代码。

代码语言:javascript
复制
 public static void main(String[] args) {        String str = "{\"TEACHER___---NAME\":\"zxerjones\"}";
        Teacher teacher = JSON.parseObject(str, Teacher.class);
        System.out.println(teacher);
    }

运行结果:

代码语言:javascript
复制
代码语言:javascript
复制
ProFastjson.Teacher(teacherName=zxerjones)

Process finished with exit code 0

猜想成立,问题解决。血一样的教训:能用 postman 就不要用单元测试。~~(╯﹏╰)~~

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-01-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java大联盟 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档