为什么POJO中变量不能用is开头

一、前言

在阿里编码规约中,有一个约定如下

【强制】POJO 类中的任何布尔类型的变量,都不要加 is 前缀,否则部分框架解析会引起序列 化错误。

但为什么类中的field不能用is开头呢?本文将从问题演示、框架源码(本文使用的Jackson)两个方面来进行阐述。

二、问题演示

本文使用的Jackson,需要引入相关依赖,maven依赖如下,gradle配置请自行寻找。

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.11.0</version>
</dependency>

首先写一个简单的POJO,在这个POJO中,有三个属性,分别是isSuccess/code/msg,并自动生成了对应的get方法,这里要注意,isSuccess属性对应的get方法名也是isSuccess()。代码如下

public class Pojo {
 
    private boolean isSuccess;
 
    private int code;
 
    private String msg;
 
    private Pojo(boolean success, int code, String msg) {
        this.isSuccess = success;
        this.code = code;
        this.msg = msg;
    }
 
    public static Pojo buildSuccess() {
        return new Pojo(true, 2000, "success");
    }
 
    public boolean isSuccess() {
        return isSuccess;
    }
 
    public int getCode() {
        return code;
    }
 
    public String getMsg() {
        return msg;
    }
 
    @Override
    public String toString() {
        return "Pojo{" +
                "isSuccess=" + isSuccess +
                ", code=" + code +
                ", msg='" + msg + '\'' +
                '}';
    }
}

然后再写一个类,在这个类中测试对POJO的序列化。在主函数中,会先创建一个POJO,然后将其打印,接着会使用Jackson中的ObjectMapper将对象序列化成Json字符串并打印。

public class Main {
 
    public static void main(String[] args) {
        ObjectMapper mapper = new ObjectMapper();
 
        Pojo pojo = Pojo.buildSuccess();
        System.out.println("raw pojo1: " + pojo.toString());
 
        try {
            System.out.println("serialize pojo1: " + mapper.writeValueAsString(pojo));
        } catch (IOException e) {
            System.out.println(e);
        }
    }
}

执行main()方法后,得到运行结果如下图:

img

可以发现,使用ObjectMapper对象将POJO序列化成String后,输出的变量名是success,而原有POJO中的变量isSuccess丢失。将该Json串反序列化成对象,会出现问题。

三、源码解析

// TODO 待源码大致读懂后再补充

源码看不太懂,只讲解一下核心的流程。由于Jackson扩展性很好,对各种复杂情况都进行了处理,这里只讲解最普通的分支流程。

主要方法是POJOPropertiesCollector#collectAll()

    protected void collectAll()
    {
        LinkedHashMap<String, POJOPropertyBuilder> props = new LinkedHashMap<String, POJOPropertyBuilder>();
 
        // First: gather basic data
        _addFields(props); // note: populates _fieldRenameMappings
        _addMethods(props);
        // 25-Jan-2016, tatu: Avoid introspecting (constructor-)creators for non-static
        //    inner classes, see [databind#1502]
        if (!_classDef.isNonStaticInnerClass()) {
            _addCreators(props);
        }
 
        // Remove ignored properties, first; this MUST precede annotation merging
        // since logic relies on knowing exactly which accessor has which annotation
        _removeUnwantedProperties(props);
        // and then remove unneeded accessors (wrt read-only, read-write)
        _removeUnwantedAccessor(props);
 
        // Rename remaining properties
        _renameProperties(props);
 
        // and now add injectables, but taking care to avoid overlapping ones
        // via creator and regular properties
        _addInjectables(props);
 
        // then merge annotations, to simplify further processing
        // 26-Sep-2017, tatu: Before 2.9.2 was done earlier but that prevented some of
        //   annotations from getting properly merged
        for (POJOPropertyBuilder property : props.values()) {
            property.mergeAnnotations(_forSerialization);
        }
 
        // And use custom naming strategy, if applicable...
        PropertyNamingStrategy naming = _findNamingStrategy();
        if (naming != null) {
            _renameUsing(props, naming);
        }
 
        // Sort by visibility (explicit over implicit); drop all but first of member
        // type (getter, setter etc) if there is visibility difference
        for (POJOPropertyBuilder property : props.values()) {
            property.trimByVisibility();
        }
 
        // and, if required, apply wrapper name: note, MUST be done after
        // annotations are merged.
        if (_config.isEnabled(MapperFeature.USE_WRAPPER_NAME_AS_PROPERTY_NAME)) {
            _renameWithWrappers(props);
        }
 
        // well, almost last: there's still ordering...
        _sortProperties(props);
        _properties = props;
        _collected = true;
    }

四、结论

通过上述论证,我们不难发现,类中的属性用is开头会导致对象序列化后产生意想不到的结果。所以在平时编码的过程中,我们不能在类变量中用is开头如: “isSuccess”,这样容易造成程序错误。

如果情况特殊,也不必墨守成规,只是需要预先判断可能产生的影响、影响范围、能否监控等问题。更特殊的情况,你可以将变量名定义为isIsSuccess,或者将isSuccess定义为public。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值