IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发工具 -> Fastjson关于is开头序列化问题 -> 正文阅读

[开发工具]Fastjson关于is开头序列化问题

问题描述

public class Demo {
    private Boolean isHot;
    private Boolean isQuick;

    public Boolean getHot() {
        return isHot;
    }

    public void setHot(Boolean hot) {
        isHot = hot;
    }

    public Boolean getQuick() {
        return isQuick;
    }

    public void setQuick(Boolean quick) {
        isQuick = quick;
    }
}

例如上面一个bean,getset方法均为idea自动生成的(Idea 2020.1),Fastjson序列化后的结果为

{
    "hot":true,
    "quick":true
}

我们其实期望的是

{
    "isHot":true,
    "isQuick":true
}

解决方案

方案一

修改get方法为getIsXXX
public Boolean getHot()->public Boolean getIsHot()

方案二

去掉getset方法使用lombok,如果公司允许的话

方案三

修改idea默认模板

image.png

#set($paramName = $helper.getParamName($field, $project))
#if($field.modifierStatic)
static ##
#end
$field.type ##
#set($name = $StringUtil.capitalizeWithJavaBeanConvention($StringUtil.sanitizeJavaIdentifier($helper.getPropertyName($field, $project))))
#if ($field.name == $paramName)
get##
#else
getIs##
#end
${name}() {
return this.##
$field.name;
}

方案四

不要以is开头,加入公司的代码规范,《Java开发手册(泰山版)》中也提到了

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

源码分析

下面我们看一下Fastjson源码

public static List<FieldInfo> computeGetters(Class<?> clazz, //
                                             JSONType jsonType, //
                                             Map<String,String> aliasMap, //
                                             Map<String,Field> fieldCacheMap, //
                                             boolean sorted, //
                                             PropertyNamingStrategy propertyNamingStrategy //
){
    Map<String,FieldInfo> fieldInfoMap = new LinkedHashMap<String,FieldInfo>();
    boolean kotlin = TypeUtils.isKotlin(clazz);
    // for kotlin
    Constructor[] constructors = null;
    Annotation[][] paramAnnotationArrays = null;
    String[] paramNames = null;
    short[] paramNameMapping = null;
    Method[] methods = clazz.getMethods();
    for(Method method : methods){
       .....此处省略
        
        //主要是这里
        if(methodName.startsWith("get")){
            if(methodName.length() < 4){
                continue;
            }
            if(methodName.equals("getClass")){
                continue;
            }
            if(methodName.equals("getDeclaringClass") && clazz.isEnum()){
                continue;
            }
            char c3 = methodName.charAt(3);
            String propertyName;
            Field field = null;
            if(Character.isUpperCase(c3) //
                    || c3 > 512 // for unicode method name
                    ){
                if(compatibleWithJavaBean){
                    //根据get方法取值
                    propertyName = decapitalize(methodName.substring(3));
                } else{
                    propertyName = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
                }
                propertyName = getPropertyNameByCompatibleFieldName(fieldCacheMap, methodName, propertyName, 3);
            } 
            
         ......再度省略
            fieldInfoMap.put(propertyName, fieldInfo);
        }
    }
    Field[] fields = clazz.getFields();
    computeFields(clazz, aliasMap, propertyNamingStrategy, fieldInfoMap, fields);
    return getFieldInfos(clazz, sorted, fieldInfoMap);
}

后面就基本上以这个名称为准了。

image.png
这个writer是通过动态生成的一个bean,所以代码无法追踪,但是它强转了下return (JavaBeanSerializer) instance;所以我们可以看下JavaBeanSerializer::write方法看下是如何把bean转成String的

    protected void write(JSONSerializer serializer, //
                      Object object, //
                      Object fieldName, //
                      Type fieldType, //
                      int features,
                      boolean unwrapped
    ) throws IOException {
        SerializeWriter out = serializer.out;

        if (object == null) {
            out.writeNull();
            return;
        }

        if (writeReference(serializer, object, features)) {
            return;
        }

        final FieldSerializer[] getters;
				//获取我们刚刚解析的成员变量c h
        if (out.sortField) {
            getters = this.sortedGetters;
        } else {
            getters = this.getters;
        }

        SerialContext parent = serializer.context;
        if (!this.beanInfo.beanType.isEnum()) {
            serializer.setContext(parent, object, fieldName, this.beanInfo.features, features);
        }

        final boolean writeAsArray = isWriteAsArray(serializer, features);

        FieldSerializer errorFieldSerializer = null;
        try {
            final char startSeperator = writeAsArray ? '[' : '{';
            final char endSeperator = writeAsArray ? ']' : '}';
            if (!unwrapped) {
                //全程添加到out里面,最后toJSONString输出的也是out
                out.append(startSeperator);
            }

            if (getters.length > 0 && out.isEnabled(SerializerFeature.PrettyFormat)) {
                serializer.incrementIndent();
                serializer.println();
            }

            boolean commaFlag = false;

            if ((this.beanInfo.features & SerializerFeature.WriteClassName.mask) != 0
                ||(features & SerializerFeature.WriteClassName.mask) != 0
                || serializer.isWriteClassName(fieldType, object)) {
                Class<?> objClass = object.getClass();

                final Type type;
                if (objClass != fieldType && fieldType instanceof WildcardType) {
                    type = TypeUtils.getClass(fieldType);
                } else {
                    type = fieldType;
                }

                if (objClass != type) {
                    writeClassName(serializer, beanInfo.typeKey, object);
                    commaFlag = true;
                }
            }

            char seperator = commaFlag ? ',' : '\0';

            final boolean writeClassName = out.isEnabled(SerializerFeature.WriteClassName);
            char newSeperator = this.writeBefore(serializer, object, seperator);
            commaFlag = newSeperator == ',';

            final boolean skipTransient = out.isEnabled(SerializerFeature.SkipTransientField);
            final boolean ignoreNonFieldGetter = out.isEnabled(SerializerFeature.IgnoreNonFieldGetter);

            for (int i = 0; i < getters.length; ++i) {
               
               .....字符串拼接
               
            }

            this.writeAfter(serializer, object, commaFlag ? ',' : '\0');

            if (getters.length > 0 && out.isEnabled(SerializerFeature.PrettyFormat)) {
                serializer.decrementIdent();
                serializer.println();
            }

            if (!unwrapped) {
                //全程添加进out里面
                out.append(endSeperator);
            }
        } catch (Exception e) {
            .....处理异常,忽略
        } finally {
            serializer.context = parent;
        }
    }
  开发工具 最新文章
Postman接口测试之Mock快速入门
ASCII码空格替换查表_最全ASCII码对照表0-2
如何使用 ssh 建立 socks 代理
Typora配合PicGo阿里云图床配置
SoapUI、Jmeter、Postman三种接口测试工具的
github用相对路径显示图片_GitHub 中 readm
Windows编译g2o及其g2o viewer
解决jupyter notebook无法连接/ jupyter连接
Git恢复到之前版本
VScode常用快捷键
上一篇文章      下一篇文章      查看所有文章
加:2021-08-02 11:00:04  更:2021-08-02 11:01:04 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/20 13:26:19-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码