问题背景:
今天在做项目联调时调用别人的第三方接口时,发现字段传递不对导致参数传递异常的问题,当时还很奇怪,明白传好着呢,怎么就好端端的出现字段不对的情况呢?
查看发现该字段为boolean类型的isIsRefresh,但传给第三方json串里字段变为了isRefresh,发现类中定义的字段确实为isIsRefresh,与设计文档上相同,并非定义错误。因此猜测是在服务传递时导致is丢失。(此处对于这个字段属性名称请大家不要喷,第三方叫这个,非常想改无奈别人的代码没法动,叫的的确不咋样,本文重点说一下为什么会出这个问题,这个问题应该如何解决、处理,请各位大佬不要追究属性名哦,也正是因为这个不规范命名才导致了此次联调失败)。
这个是我传的值:
这个是对方接口接收到的值:(命名凑合看)
这个是我的实体Bean:
明显是有区别的,两个is变成了一个is,导致对方接口参数校验失败,(除了命名之外看着是没有问题的,但就是传值不对)
原因分析:
JavaBean类的属性的类型是boolean类型,那么该属性的读方法的格式可以是isXxx()或者getXxx(),例如,名为state的boolean类型的属性,它的读方法可以是isState()或者是getState()。
【强制】POJO 类中的任何布尔类型的变量,都不要加 is 前缀,否则部分框架解析会引起序列化错误。
反例:定义为基本数据类型 Boolean isDeleted 的属性,它的方法也是 isDeleted(),框架在反向解析的时候,“误以为”对应的属性名称是 deleted,导致属性获取不到,进而抛出异常。
问题验证:
定义一个实体类BeanTest,含有boolean的属性isSuccess 和 String类型的属性name,使用Lombok框架来生成getter、setter和constructor。测试方法分别使用Gson、Fastjson和Jackson来进行序列化,测试结果如下。
@Data
class BeanTest {private String name;private boolean isSuccess;private boolean isFlag;public BeanTest(String name, boolean isSuccess, boolean isFlag) {this.name = name;this.isSuccess = isSuccess;this.isFlag = isFlag;}public BeanTest() {}public static void main(String[] args) throws JsonProcessingException {BeanTest bean = new BeanTest("allen",true,false);//GsonString gsonString = new Gson().toJson(bean);System.out.println("Gson: " + gsonString);//fastjsonString fastJsonString = JSON.toJSONString(bean);System.out.println("Fastjson: " + fastJsonString);//JacksonString jacksonString = new ObjectMapper().writeValueAsString(bean);System.out.println("Jackson: " + jacksonString);}
}
执行结果:
Gson: {"name":"allen","isSuccess":true,"isFlag":false}
Fastjson: {"flag":false,"name":"allen","success":true}
Jackson: {"name":"allen","success":true,"flag":false}
可以看出使用Gson序列化后的json串没有出现is丢失的问题,而jackson和fastjson均出现了is丢失的问题,Gson是根据类中属性进行序列化,所以结果没什么问题。而Jackson和FastJson的序列化方式是先找到getter方法,再根据JavaBean规范生成对应的属性名,所以不仅isBooTest属性被序列化成booTest且testAtt这个类中根本不存在的属性也在序列化的结果中。
解决方案:
经过测试发现对于jackson和fastjson会出现一下几种情况,而gson在这些情景下都可以正确的序列化 。
1.is开头的非boolean类型字段,使用getIsXXX方法,序列化后字段名不变
2.is开头的非boolean类型字段,使用isXXX方法,序列化之后消失
3.is开头的boolean类型字段,使用getIsXXX方法,序列化之后字段名不变
4.is开头的boolean类型字段,使用isXXX方法,序列化之后字段名前的is被去除
若要避免该问题,有以下几种方法
方法1:bean的boolean属性设置时不要以is作为小驼峰;
方法2:不要使用@Data生成getter,应该使用快捷键生成,然后手动修改成getIsXxx()的形式;
方法3:使用Gson序列化对象;
方法4:bean的布尔类型属性设置为包装类型Boolean,而不要使用boolean。使用Boolean时@Data生成的getter和setter为getIsXxx(), setIsXxx()。
对于这个问题,我还是要说一句:既然有规范请严格按照规范,起这种命名害人害己,请大家谨记,以下是阿里开发规范,仅供参考!!!!
注释:RPC(Remote Procedure Call,远程过程调用)是一个计算机通信协议。
- RPC 是一种基于 TCP 传输层或者 HTTP2 应用层的通信协议;
- HTTP 只基于 HTTP 协议,包括 HTTP1.x(即 HTTP1.0、1.1) 和 HTTP2,目前很多浏览器默认使用 1.x 来访问服务器数据。
当然你要是实在迫不得已没办法了,这么做也是可以改成的,但并不建议!
https://blog.csdn.net/yangf257/article/details/131209619