jackson json序列化实现首字母大写,第二个字母需小写


Posted in Java/Android onJune 29, 2021

有这样一个类:

@Setter
@Getter
@JsonNaming(value = PropertyNamingStrategy.UpperCamelCaseStrategy.class)
public class Student {

    private String bName;

}

序列化后,希望首字母大写,如下面的测试代码:

@Test
    public void contextLoads() throws IOException {

        Student test = new Student();
        test.setBName("234234");

        String s = objectMapper.writeValueAsString(test);

        Assert.assertEquals("{\"BName\":\"234234\"}", s);

    }

可实际运行后,结果与希望不一样:

org.junit.ComparisonFailure:

Expected :{"BName":"234234"}

Actual   :{"Bname":"234234"}

jackson在序列化时把第二个大写字母n转成了小写,这是为什么呢?

以下是跟踪源码的过程:

直接找到:com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector#collectAll这个方法:

jackson json序列化实现首字母大写,第二个字母需小写

 

执行完_addFields(props)方法后:

jackson json序列化实现首字母大写,第二个字母需小写

执行完_addMethods(props)方法后:

jackson json序列化实现首字母大写,第二个字母需小写

 

一个是bName,一个是bname;

第一个bName取的是字段的名称,

第二个bname是取的它的set方法:

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;
    }

根据stdNaming来决定这个name是以什么标准输出,默认的是false;

stdManglePropertyName 就是原始输出。

legacyManglePropertyName 就是规范输出。

下面的代码就是规范输出:

protected static String legacyManglePropertyName(final String basename, final int offset)
    {
        final int end = basename.length();
        if (end == offset) { // empty name, nope
            return null;
        }
        // next check: is the first character upper case? If not, return as is
        char c = basename.charAt(offset);
        char d = Character.toLowerCase(c);
        
        if (c == d) {
            return basename.substring(offset);
        }
        // otherwise, lower case initial chars. Common case first, just one char
        StringBuilder sb = new StringBuilder(end - offset);
        sb.append(d);
        int i = offset+1;
        for (; i < end; ++i) {
            c = basename.charAt(i);
            d = Character.toLowerCase(c);
            if (c == d) {
                sb.append(basename, i, end);
                break;
            }
            sb.append(d);
        }
        return sb.toString();
    }

主要逻辑在for循环中,去除set后,第一个字母小写,

第二字母小写后,与第二个字母比较,如果都是小写,则直接接上,返回,

如果第二字母大写,就如我们的这种情况,就以小写的情况,接上,再去找下一个字母,直到找到小写字母为止。

意思就是为了满足驼峰命名规则,要规范输出。

 

如果我们的字段命名正如它的规范的话,props是只有一条记录的,因为:名称相同,就不插入了,由于咱们的名称不同,所以就有两条记录。

protected POJOPropertyBuilder _property(Map<String, POJOPropertyBuilder> props,
            String implName)
    {
        POJOPropertyBuilder prop = props.get(implName);
        if (prop == null) {
            prop = new POJOPropertyBuilder(_config, _annotationIntrospector, _forSerialization,
                    PropertyName.construct(implName));
            props.put(implName, prop);
        }
        return prop;
    }

 

可是我们输出中只有一条,没有bName这条,

jackson json序列化实现首字母大写,第二个字母需小写

 

其实在是这里把第一条删除了。因为:

jackson json序列化实现首字母大写,第二个字母需小写

 

这些属性为空,导致这个字段不可见:

protected void _removeUnwantedProperties(Map<String, POJOPropertyBuilder> props)
    {
        Iterator<POJOPropertyBuilder> it = props.values().iterator();
        while (it.hasNext()) {
            POJOPropertyBuilder prop = it.next();

            // First: if nothing visible, just remove altogether
            if (!prop.anyVisible()) {
                it.remove();
                continue;
            }
            // Otherwise, check ignorals
            if (prop.anyIgnorals()) {
                // first: if one or more ignorals, and no explicit markers, remove the whole thing
                if (!prop.isExplicitlyIncluded()) {
                    it.remove();
                    _collectIgnorals(prop.getName());
                    continue;
                }
                // otherwise just remove ones marked to be ignored
                prop.removeIgnored();
                if (!prop.couldDeserialize()) {
                    _collectIgnorals(prop.getName());
                }
            }
        }
    }

 

只剩第二记录bname,再首字母大写,所以就是Bname了。

解决方案:

第一个就是JsonProperty

@Setter
@Getter
@JsonNaming(value = PropertyNamingStrategy.UpperCamelCaseStrategy.class)
public class Student {

    @JsonProperty("BName")
    private String bName;

}

测试结果如下:

org.junit.ComparisonFailure:

Expected :{"BName":"234234"}

Actual   :{"Bname":"234234","BName":"234234"}

 

虽然生成了BName,但是Bname仍在(加了JsonProperty就visable了)。

 

第二个就是配置objectMapper的MapperFeature.USE_STD_BEAN_NAMIN如上文提到了,非规范化输出。

如下代码:

@Test
    public void contextLoads() throws IOException {

        Student test = new Student();
        test.setBName("234234");
        objectMapper.configure(MapperFeature.USE_STD_BEAN_NAMING, true);
        String s = objectMapper.writeValueAsString(test);

        Assert.assertEquals("{\"BName\":\"234234\"}", s);

    }

第三个方案:重写PropertyNamingStrategy:

@Test
    public void contextLoads() throws IOException {

        Student test = new Student();
        test.setBName("234234");
        //objectMapper.configure(MapperFeature.USE_STD_BEAN_NAMING, true);

        objectMapper.setPropertyNamingStrategy(new PropertyNamingStrategy() {
            private static final long serialVersionUID = 1L;
            // 反序列化时调用
            @Override
            public String nameForSetterMethod(MapperConfig<?> config,
                                              AnnotatedMethod method, String defaultName) {
                return method.getName().substring(3);
            }
            // 序列化时调用
            @Override
            public String nameForGetterMethod(MapperConfig<?> config,
                                              AnnotatedMethod method, String defaultName) {
                return method.getName().substring(3);
            }
        });


        String s = objectMapper.writeValueAsString(test);

        Assert.assertEquals("{\"BName\":\"2342344\"}", s);

    }

修改objectMapper的配置,要注意对其他功能的影响。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Java/Android 相关文章推荐
Java并发编程必备之Future机制
Jun 30 Java/Android
解决MultipartFile.transferTo(dest) 报FileNotFoundExcep的问题
Jul 01 Java/Android
深入浅出讲解Java8函数式编程
Jan 18 Java/Android
关于Mybatis中SQL节点的深入解析
Mar 19 Java/Android
详解Flutter和Dart取消Future的三种方法
Apr 07 Java/Android
Java8 Stream API 提供了一种高效且易于使用的处理数据的方式
Apr 13 Java/Android
JavaScript正则表达式实现注册信息校验功能
May 30 Java/Android
Ubuntu18.04下QT开发Android无法连接设备问题解决实现
Jun 01 Java/Android
java实现自定义时钟并实现走时功能
Jun 21 Java/Android
Spring Cloud OpenFeign模版化客户端
Jun 25 Java/Android
java中如何截取字符串最后一位
Jul 07 Java/Android
Android移动应用开发指南之六种布局详解
Sep 23 Java/Android
Java数组与堆栈相关知识总结
分析JVM源码之Thread.interrupt系统级别线程打断
Jun 29 #Java/Android
Jackson 反序列化时实现大小写不敏感设置
Jun 29 #Java/Android
Maven学习----Maven安装与环境变量配置教程
Spring Boot两种全局配置和两种注解的操作方法
Spring Boot 实现敏感词及特殊字符过滤处理
Jun 29 #Java/Android
elasticSearch-api的具体操作步骤讲解
You might like
解析PHP无限级分类方法及代码
2013/06/21 PHP
自己写的php中文截取函数mb_strlen和mb_substr
2015/02/09 PHP
PHP实现获取并生成数据库字典的方法
2016/05/04 PHP
PHP实现的简单对称加密与解密方法实例小结
2017/08/28 PHP
JS获取地址栏参数的小例子
2013/08/23 Javascript
特殊情况下如何获取span里面的值
2014/05/20 Javascript
JavaScript获取页面上被选中文字的方法技巧
2015/03/13 Javascript
jquery实现全选、反选、获得所有选中的checkbox
2020/09/13 Javascript
高效的jquery数字滚动特效
2015/12/17 Javascript
js仿微信语音播放实现思路
2016/12/12 Javascript
vue安装遇到的5个报错及解决方法
2019/06/12 Javascript
vuex存储复杂参数(如对象数组等)刷新数据丢失的解决方法
2019/11/05 Javascript
[01:01:41]DOTA2-DPC中国联赛 正赛 PSG.LGD vs Magma BO3 第二场 1月31日
2021/03/11 DOTA
Python中文件操作简明介绍
2015/04/13 Python
Python应用03 使用PyQT制作视频播放器实例
2016/12/07 Python
python检查URL是否正常访问的小技巧
2017/02/25 Python
python使用xpath中遇到:到底是什么?
2018/01/04 Python
转换科学计数法的数值字符串为decimal类型的方法
2018/07/16 Python
Python Web编程之WSGI协议简介
2018/07/18 Python
python使用matplotlib绘制热图
2018/11/07 Python
浅谈pycharm的xmx和xms设置方法
2018/12/03 Python
python实现祝福弹窗效果
2019/04/07 Python
Python如何筛选序列中的元素的方法实现
2019/07/15 Python
Python PyQt5 Pycharm 环境搭建及配置详解(图文教程)
2019/07/16 Python
python删除列表元素的三种方法(remove,pop,del)
2019/07/22 Python
python编写计算器功能
2019/10/25 Python
Python脚本破解压缩文件口令实例教程(zipfile)
2020/06/14 Python
CSS3中box-shadow的用法介绍
2015/07/15 HTML / CSS
HTML5新增元素如何兼容旧浏览器有哪些方法
2014/05/09 HTML / CSS
Smashbox官网:美国知名彩妆品牌
2017/01/05 全球购物
在线吉他课程,学习如何弹吉他:Fender Play
2019/02/28 全球购物
店长职务说明书
2014/02/04 职场文书
原材料检验岗位职责
2014/03/15 职场文书
禁毒宣传工作方案
2014/05/23 职场文书
如何写股份合作协议书
2014/09/11 职场文书
2014年生活老师工作总结
2014/12/23 职场文书