记一次接口交互is开头的属性序列化后“is”丢失问题

问题背景:

今天在做项目联调时调用别人的第三方接口时,发现字段传递不对导致参数传递异常的问题,当时还很奇怪,明白传好着呢,怎么就好端端的出现字段不对的情况呢?

查看发现该字段为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);

        //Gson
        String gsonString = new Gson().toJson(bean);
        System.out.println("Gson: " + gsonString);

        //fastjson
        String fastJsonString = JSON.toJSONString(bean);
        System.out.println("Fastjson: " + fastJsonString);

        //Jackson
        String 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

  • 24
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
判断一个类是否需要实现序列化接口,可以考虑以下几个因素: 1. 是否需要在网络传输中使用:如果你的类需要在网络传输中使用,例如通过Socket进行通信或者远程方法调用(RMI),那么需要实现序列化接口。因为在网络传输过程中,对象需要被转换成字节流进行传输。 2. 是否需要持久化到磁盘:如果你的类需要被保存到文件系统或数据库中,以便于后续读取和恢复对象状态,那么需要实现序列化接口。通过序列化,可以将对象转换为字节流,并将其写入文件或数据库。 3. 是否需要进行对象复制或克隆:如果你的类需要进行对象的复制或克隆操作,那么可能需要实现序列化接口。通过序列化和反序列化,可以实现深拷贝,即创建一个与原始对象完全相同的新对象。 4. 是否需要在分布式环境中使用:如果你的类需要在分布式系统中使用,例如将对象从一个节点传输到另一个节点,那么需要实现序列化接口。因为在分布式环境中,对象需要在不同的机器之间进行传输和交互。 需要注意的是,并不是所有的类都需要实现序列化接口。有些类可能包含敏感信息或者无法序列化的成员变量,这些类可以选择不实现序列化接口或使用transient关键字修饰不需要序列化的成员变量。在判断是否需要实现序列化接口时,需要考虑类的使用场景和需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Alex_81D

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

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

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

打赏作者

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

抵扣说明:

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

余额充值