SpringMVC中Controller接口返回json的字段(field)名称突然变了

一、前言

最近线上系统突然出现一个了离奇的事情。线上有个接口返回的json中,一个字段的名称突然从data变成了result。从而导致前端代码无法正确解析处理数据,业务无法正常展示。如下图:之前返回的结构中数据节点为data。

 然后现在该i节点突然变成了result。

 经过检查代码发现最近都没有修改相关代码,该接口返回json中涉及到的所有对象都没有变更过。那么这到底是怎么回事呢?接下来咱们就一起来分析一下该问题?

二、分析与总结

1、根因分析

首先我们查看对应的代码发现上面提到的data字段其实是Page对象中的一个属性。如下图,Page中的存在data字段。所以返回data也说得通。

但是result又是怎么来的呢?继续分析代码发现,data属性对应的getter方法并不叫做getData。而是叫做getResult(是不是很坑)。

所以我们基本可以得出结论:原来对象转JSON的时候是取的field的名称作为JSON中属性名称(即data),而现在是取的getter方法的中的属性名称(即result)。

由于前后我们并没有修改过代码,所以肯定不是代码导致的。但是了解到最近系统有做一系列的jar包升级。所以由此分析看来,是由于jar包的变动导致了对象在转json的时候属性取值方式不一样。

那为什么会出现这样的情况呢?想要进一步解答该问题,我们需要先了解SpringMVC中返回对象被转换为JSON串的流程。

2、SpringMVC如何将返回值转换为JSON串

PS:由于SpringMVC对入参和返回值的处理逻辑比较复杂,且也不是本文的重点。所以本章节咱们只基本介绍下其流程,不进行深入分析。

通过上图(图片来自网络)中SpringMVC的数据流向图,我们可以知道请求和返回对象都会经过HttpMessageConverter处理。

而SpringMVC的HttpMessageConverter在初始RequestMappingHandlerAdapter的时候构建。

其中AllEncompassingFormHttpMessageConverter可以理解为一个组合模式。其根据应用中不同的jar加载不同的HttpMessageConverter。

下图红框中就是针对json注入的HttpMessageConverter。这也是为什么咱们都说SpringMVC默认是使用的jackson来实现对象转json串的转换逻辑。

这段逻辑大致的意思是:如果jackson包存在,就使用Jackson来解析json;如果不存在而gson存在,则使用gson来解析对象。 

3、具体原因分析

熟悉了SpringMVC对json的处理逻辑之后,我们首先检查咱们jar升级之前工程中是否有jackson的jar包,如下图。

虽然 有jackson*asl的包。但是这个jar并不对SpringMVC的逻辑产生影响。因为jackson*asl的jar中的ObjectMapper(jackson解析对象的主类)的包路径为:org.codehaus.jackson.map.ObjectMapper。而标准的jackson的jar包中ObjectMapper类的路径com.fasterxml.jackson.databind.ObjectMapper。

在SpringMVC中其也是判断的com.fasterxml.jackson.databind.ObjectMapper这个路径。

 所以虽然代码中引入了jackson*asl的jar包。但是它不是标准的jackson包。所以SpringMVC在加载的过程中,会认为没有jsckson包,然后继续判断gson包。由于工程中存在gson的包。所以最终选择了GsonHttpMessageConverter来处理对象和json串。

 而在最新的代码工程中我们可以也确实看到了标准的jackson包(jackson-core)。

接下来我们就一起看下gson和jackson在处理对象和json串转换的时候有什么不同?

4、gson和jackson的转换差异 

我们在本地模拟下上述场景。然后分别用gson和jackson将对象转换为json串。

首先我们构造一个Person类。其name字段的getter方法名叫做GetterName(模拟线上问题中data和result的场景)。

然后编写如下测试代码:

  通过Gson将其对象转换为json串的结果如下:

使用Jackson将其对象转换为json串的结果如下:

由此我们可以看到Gson和Jackson的转换结果完全不一样。Gson使用了属性名作为json串中的名称,而Jackson则使用了Getter中的名称作为json串中的名称。

5、问题总结

所以该问题出现的原因可以简单归纳为:最开始我们的代码工程中没有引入jackson的jar包(也许是引错了)。导致了SpringMVC使用Gson来处理对象和json串之间的转换。而Gson处理对象的时候,默认是将字段的名称作为json串中的名称。

而后续jar包变动将jackson的包引入到了代码工程中,此时SpringMVC则使用jackson来处理对象和json串之间的转换。而jackson默认是使用getter中的名称作为json串中的名称。

所以最终导致了代码在没有任何变动的情况下,返回的json串中的字段名称不一致(我们的字段名称和getter中的名称不一致)。

6、如何避免该问题

通过上述分析我们知道其实最根本的原因还是因为对象中属性字段的名称和其getter中的名称不一致。所以我们在实际开发过程中要尽量避免字段名称和getter或者setter名称不一致

该问题分析就到这里,最后给大家留一个思考题:咱们在用jackson处理对象和json串的转换时,如何让jackson以字段名称作为json中的字段名,而不是以getter中的名称作为json串中的字段名。

三、惯例

如果你喜欢本文或觉得本文对你有所帮助,欢迎一键三连支持,非常感谢。

如果你对本文有任何疑问或者高见,欢迎添加公众号lifeofcoder共同交流探讨(添加公众号可以获得楼主最新博文推送以及”Java高级架构“上10G视频和图文资料哦)。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

跳小闹成长记-跳爸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值