POJO 类中布尔类型为啥不让用 isXxx 命名

一、代码问题重现

 

想要使用json串在服务间传递信息时,我们会先定义一个POJO类,该类中包含是否删除属性isDeleted,代码如下

/**

 * @author wenxuan wang

 */

 

@Data

public class ResultVO {

 

    private boolean isDeleted;

 

    private Integer errorCode;

 

    private String errorMsg;

 

}

构建出该类的对象并使用jackson将该对象序列化,结果如下:

 

{

    "errorCode":101,

    "errorMsg":"参数错误",

    "deleted":false

}

 

isDeleted的is没有了。

二、追根溯源

 

ResultVO经过lombok的@Data注解自动生成getter,setter函数,class文件如下

 

//

// Source code recreated from a .class file by IntelliJ IDEA

// (powered by Fernflower decompiler)

//

 

 

public class ResultVO {

    private boolean isDeleted;

    private Integer errorCode;

    private String errorMsg;

 

    public ResultVO() {

    }

 

    public boolean isDeleted() {

        return this.isDeleted;

    }

 

    public Integer getErrorCode() {

        return this.errorCode;

    }

 

    public String getErrorMsg() {

        return this.errorMsg;

    }

 

    public void setDeleted(boolean isDeleted) {

        this.isDeleted = isDeleted;

    }

 

    public void setErrorCode(Integer errorCode) {

        this.errorCode = errorCode;

    }

 

    public void setErrorMsg(String errorMsg) {

        this.errorMsg = errorMsg;

    }

 

    public boolean equals(Object o) {

        if (o == this) {

            return true;

        } else if (!(o instanceof ResultVO)) {

            return false;

        } else {

            ResultVO other = (ResultVO)o;

            if (!other.canEqual(this)) {

                return false;

            } else if (this.isDeleted() != other.isDeleted()) {

                return false;

            } else {

                Object this$errorCode = this.getErrorCode();

                Object other$errorCode = other.getErrorCode();

                if (this$errorCode == null) {

                    if (other$errorCode != null) {

                        return false;

                    }

                } else if (!this$errorCode.equals(other$errorCode)) {

                    return false;

                }

 

                Object this$errorMsg = this.getErrorMsg();

                Object other$errorMsg = other.getErrorMsg();

                if (this$errorMsg == null) {

                    if (other$errorMsg != null) {

                        return false;

                    }

                } else if (!this$errorMsg.equals(other$errorMsg)) {

                    return false;

                }

 

                return true;

            }

        }

    }

 

    protected boolean canEqual(Object other) {

        return other instanceof ResultVO;

    }

 

    public int hashCode() {

        int PRIME = true;

        int result = 1;

        int result = result * 59 + (this.isDeleted() ? 79 : 97);

        Object $errorCode = this.getErrorCode();

        result = result * 59 + ($errorCode == null ? 43 : $errorCode.hashCode());

        Object $errorMsg = this.getErrorMsg();

        result = result * 59 + ($errorMsg == null ? 43 : $errorMsg.hashCode());

        return result;

    }

 

    public String toString() {

        return "ResultVO(isDeleted=" + this.isDeleted() + ", errorCode=" + this.getErrorCode() + ", errorMsg=" + this.getErrorMsg() + ")";

    }

}

 

可以看出isDeleted本来的get/set格式getIsDeleted/setIsDeleted,经过自动生成后变成isDeleted/setDeleted,万恶之源(编译器会对boolean类型的get/set进行优化)

 

三、源码解析

 

深入解析jackson的源码,可以发现如下代码

 

    /**

     * @since 2.5

     */

    public static String okNameForRegularGetter(AnnotatedMethod am, String name,

            boolean stdNaming)

    {

        if (name.startsWith("get")) {

            /* 16-Feb-2009, tatu: To handle [JACKSON-53], need to block

             *   CGLib-provided method "getCallbacks". Not sure of exact

             *   safe criteria to get decent coverage without false matches;

             *   but for now let's assume there's no reason to use any

             *   such getter from CGLib.

             *   But let's try this approach...

             */

            if ("getCallbacks".equals(name)) {

                if (isCglibGetCallbacks(am)) {

                    return null;

                }

            } else if ("getMetaClass".equals(name)) {

                // 30-Apr-2009, tatu: Need to suppress serialization of a cyclic reference

                if (isGroovyMetaClassGetter(am)) {

                    return null;

                }

            }

            return stdNaming

                    ? stdManglePropertyName(name, 3)

                    : legacyManglePropertyName(name, 3);

        }

        return null;

    }

 

    /**

     * @since 2.5

     */

    public static String okNameForIsGetter(AnnotatedMethod am, String name,

            boolean stdNaming)

    {

        if (name.startsWith("is")) { // plus, must return a boolean

            Class<?> rt = am.getRawType();

            if (rt == Boolean.class || rt == Boolean.TYPE) {

                return stdNaming

                        ? stdManglePropertyName(name, 2)

                        : legacyManglePropertyName(name, 2);

            }

        }

        return null;

    }

 

    /**

     * @since 2.5

     */

    @Deprecated // since 2.9, not used any more

    public static String okNameForSetter(AnnotatedMethod am, boolean stdNaming) {

        String name = okNameForMutator(am, "set", stdNaming);

        if ((name != null)

            // 26-Nov-2009, tatu: need to suppress this internal groovy method

                && (!"metaClass".equals(name) || !isGroovyMetaClassSetter(am))) {

            return name;

        }

        return null;

    }

 

    /**

     * @since 2.5

     */

    public static String okNameForMutator(AnnotatedMethod am, String prefix,

            boolean stdNaming) {

        String name = am.getName();

        if (name.startsWith(prefix)) {

            return stdNaming

                    ? stdManglePropertyName(name, prefix.length())

                    : legacyManglePropertyName(name, prefix.length());

        }

        return null;

    }

jackson会根据VOget/set函数来对VO进行序列化/反序列化。可以看出,如果是Boolean类型的变量,会将isDeleted的前缀is去掉,剩下的deleted作为反序列化key,而将setDeleted的前缀set去掉,剩下的deleted作为序列化key

 

很多编译器的get/set的自动生成结果与标准结果有偏差,很多json序列化方法都使用和jackson相似的模式对序列化/反序列化过程进行优化,所以POJO 类中布尔类型最好不要用 isXxx 命名

 

就好像有一个残疾人,编译器也想给他加一只手,jackson也想给他加一只手,这个残疾人反而变得更不正常了

 

 

 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值