“布尔类型的变量名不要加is前缀”原理解析

最近阅读公司的规范,发现了这样的一条:

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

如果读者研发的产品正在大量使用阿里系框架,这个问题就需要十分注意。

我们假设一个场景,设计文档中设计了一个类,其中某个field命名为 isXx:

这时,对于前端后分离的项目,前端认为你返回的json中将存在一个 Key为 “isXx”的value。后端亦是如此开发。

Class SomeClass{
boolean isXx;
/...
}

如果使用FastJson框架序列化SomeClass类的实例对象。直观理论上,应该返回前端一个:

{
    "isXx" : true/false
}

然而实际上,前端获取到的json数据为:

{
    "Xx" : true/false
}

显然,前后端都按设计文档开发了,直观理论无误。那么问题,就出在了传递的过程。

通过阅读FastJson源码,发现:

//com.alibaba.fastjson.util.TypeUtils.computeGetters

if (methodName.startsWith("is")) {
                if (methodName.length() < 3) {
                    continue;
                }
                if (returnType != Boolean.TYPE
                        && returnType != Boolean.class) {
                    continue;
                }
                char c2 = methodName.charAt(2);
                String propertyName;
                Field field = null;
                if (Character.isUpperCase(c2)) {
                    if (compatibleWithJavaBean) {
                        propertyName = decapitalize(methodName.substring(2));
                    } else {
                        propertyName = Character.toLowerCase(methodName.charAt(2)) + methodName.substring(3);
                    }
                    propertyName = getPropertyNameByCompatibleFieldName(fieldCacheMap, methodName, propertyName, 2);
                } else if (c2 == '_') {
                    propertyName = methodName.substring(3);
                    field = fieldCacheMap.get(propertyName);
                    if (field == null) {
                        String temp = propertyName;
                        propertyName = methodName.substring(2);
                        field = ParserConfig.getFieldFromCache(propertyName, fieldCacheMap);
                        if (field == null) {
                            propertyName = temp;
                        }
                    }
                } else if (c2 == 'f') {
                    propertyName = methodName.substring(2);
                } else {
                    propertyName = methodName.substring(2);
                    field = ParserConfig.getFieldFromCache(propertyName, fieldCacheMap);
                    if (field == null) {
                        continue;
                    }
                }
                boolean ignore = isJSONTypeIgnore(clazz, propertyName);
                if (ignore) {
                    continue;
                }

                if (field == null) {
                    field = ParserConfig.getFieldFromCache(propertyName, fieldCacheMap);
                }

                if (field == null) {
                    field = ParserConfig.getFieldFromCache(methodName, fieldCacheMap);
                }
                JSONField fieldAnnotation = null;
                if (field != null) {
                    fieldAnnotation = TypeUtils.getAnnotation(field, JSONField.class);
                    if (fieldAnnotation != null) {
                        if (!fieldAnnotation.serialize()) {
                            continue;
                        }
                        ordinal = fieldAnnotation.ordinal();
                        serialzeFeatures = SerializerFeature.of(fieldAnnotation.serialzeFeatures());
                        parserFeatures = Feature.of(fieldAnnotation.parseFeatures());
                        if (fieldAnnotation.name().length() != 0) {
                            propertyName = fieldAnnotation.name();
                            if (aliasMap != null) {
                                propertyName = aliasMap.get(propertyName);
                                if (propertyName == null) {
                                    continue;
                                }
                            }
                        }
                        if (fieldAnnotation.label().length() != 0) {
                            label = fieldAnnotation.label();
                        }
                    }
                }
                if (aliasMap != null) {
                    propertyName = aliasMap.get(propertyName);
                    if (propertyName == null) {
                        continue;
                    }
                }
                if (propertyNamingStrategy != null) {
                    propertyName = propertyNamingStrategy.translate(propertyName);
                }
                //优先选择get
                if (fieldInfoMap.containsKey(propertyName)) {
                    continue;
                }
                FieldInfo fieldInfo = new FieldInfo(propertyName, method, field, clazz, null, ordinal, serialzeFeatures, parserFeatures,
                        annotation, fieldAnnotation, label);
                fieldInfoMap.put(propertyName, fieldInfo);
            }

 逻辑并不复杂,判断以 'is'开头时,会从'is'后截取作为PropertyName。

源码中没有注释解释为何要这么做,作者理解为这与setter/getter构造原理相似,都是通过规范去反射实现功能。

Spring框架中依赖注入也有类似的原理。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值