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输出Hello World完美过程解析
Jun 13 Java/Android
logback 实现给变量指定默认值
Aug 30 Java/Android
java中用float时,数字后面加f,这样是为什么你知道吗
Sep 04 Java/Android
Java Spring 控制反转(IOC)容器详解
Oct 05 Java/Android
详解JAVA的控制语句
Nov 11 Java/Android
你知道Java Spring的两种事务吗
Mar 16 Java/Android
剑指Offer之Java算法习题精讲二叉树的构造和遍历
Mar 21 Java/Android
MyBatis配置文件解析与MyBatis实例演示
Apr 07 Java/Android
springboot读取nacos配置文件
May 20 Java/Android
详解Spring Bean的配置方式与实例化
Jun 10 Java/Android
Mybatis-plus配置分页插件返回统一结果集
Jun 21 Java/Android
详解Spring Security如何在权限中使用通配符
Jun 28 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获取远程图片并把它保存到本地的代码
2008/04/07 PHP
使用php shell命令合并图片的代码
2011/06/23 PHP
JSON在PHP中的应用介绍
2012/09/08 PHP
php读取图片内容并输出到浏览器的实现代码
2013/08/08 PHP
叫你如何修改Nginx与PHP的文件上传大小限制
2014/09/10 PHP
PHP session垃圾回收机制实例分析
2019/06/28 PHP
用JTrackBar实现的模拟苹果风格的滚动条
2007/08/06 Javascript
JavaScript 常见对象类创建代码与优缺点分析
2009/12/07 Javascript
javascript搜索框点击文字消失失焦时文本出现
2014/09/18 Javascript
javascript实现的图片切割多块效果实例
2015/05/07 Javascript
简介JavaScript中search()方法的使用
2015/06/06 Javascript
jQuery自适应轮播图插件Swiper用法示例
2016/08/24 Javascript
JS继承之借用构造函数继承和组合继承
2016/09/07 Javascript
js中字符型和数值型数字的互相转化方法(必看)
2017/04/25 Javascript
Linux系统中利用node.js提取Word(doc/docx)及PDF文本的内容
2017/06/17 Javascript
Vue单文件组件的如何使用方式介绍
2017/07/28 Javascript
vue实现商城购物车功能
2017/11/27 Javascript
Vue实现类似Spring官网图片滑动效果方法
2019/03/01 Javascript
[43:35]EG vs Winstrike 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
[01:11:28]DOTA2-DPC中国联赛定级赛 RNG vs Phoenix BO3第一场 1月8日
2021/03/11 DOTA
跟老齐学Python之重回函数
2014/10/10 Python
Python实现的生成格雷码功能示例
2018/01/24 Python
Django自定义过滤器定义与用法示例
2018/03/22 Python
win10下tensorflow和matplotlib安装教程
2018/09/19 Python
pandas把所有大于0的数设置为1的方法
2019/01/26 Python
python协程gevent案例 爬取斗鱼图片过程解析
2019/08/27 Python
python使用多线程编写tcp客户端程序
2019/09/02 Python
Django后台管理系统的图文使用教学
2020/01/20 Python
Ray-Ban雷朋美国官网:全球领先的太阳眼镜品牌
2016/07/20 全球购物
斯洛伐克最大的婴儿食品和用品网上商店:Feedo.sk
2020/12/21 全球购物
文员自我评价怎么写
2013/09/19 职场文书
化学专业毕业生自荐信
2013/11/15 职场文书
微博营销计划书
2014/01/10 职场文书
七一党日活动总结
2014/07/08 职场文书
2014年招生工作总结
2014/11/26 职场文书
剖析后OpLog订阅MongoDB的数据变更就没那么难了
2022/02/24 MongoDB