jackson(json序列化实现首字母大写,第二个字母需小写)
jackson,json序列化实现首字母大写,第二个字母需小写,恰卡网带你了解更多相关信息。
有这样一个类:
@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这个方法:
执行完_addFields(props)方法后:
执行完_addMethods(props)方法后:
一个是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这条,
其实在是这里把第一条删除了。因为:
这些属性为空,导致这个字段不可见:
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的配置,要注意对其他功能的影响。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持趣讯吧。
推荐阅读
-
手动挡汽车换挡速度达到多少合适(手动挡汽车的换挡速度该如何掌握)
手动挡汽车换挡速度的合适性是很多新手司机关心的问题。一般来说,手动挡汽车的换挡速度应该尽可能平稳,避免过快或过慢。具体而言,手动挡...
-
怎么得到兄弟的女朋友 睡兄弟老婆的方法介绍
如果是真心喜欢,既然人家已经有老公了,不建议去破坏人家家庭,默默祝福就好了。运用特殊手段是违法犯罪行为,合理表达自己的爱慕之心,真...
-
查看路由器宽带密码(如何找回路由器管理员密码)
如何查看路由器宽带密码?路由器是现代家庭和企业网络中必不可少的设备。它可以连接多个设备并实现共享网络资源。但是,有时我们需要查看路...
-
失业大军涌入外卖(骑手收入腰斩 外卖骑手感到无力和绝望)
近年来,随着中国经济的不断发展和消费习惯的转变,外卖行业在中国蓬勃发展。越来越多的人加入到外卖行业中,骑手数量也大量涌入。但现在,...
-
真皮皮鞋怎么保养(正确保养真皮皮鞋的小贴士)
皮鞋在我们的日常生活中是常见的鞋履之一,不仅款式多样,而且舒适耐穿。其中,真皮皮鞋是许多人的选择,因为它们具有高品质和永久耐用的特...
-
车改装了找黄牛(汽车改装需谨慎避免找黄牛)
车改装了找黄牛汽车改装是车主展示个人品味和个性的一种方式。然而,如果改装不当,不仅会影响车辆性能和安全,而且还会面临违法处罚的风险...
-
网卡怎么用在路由器上(如何在路由器上使用网卡)
对于一些家庭用户,如果家里的网络需要多个设备同时连接上网,那么路由器无疑是一个必不可少的工具。而网卡则是路由器中非常关键的一部分。...
-
龙城陈宇呈东霓为什么离婚(龙城陈宇呈是个什么样的人)
龙城中陈宇呈是郑东霓第一任丈夫,她们是自由恋爱后面离婚了,陈宇呈35岁,龙城血液中心医生。冷静理智,作为一个优秀的医生,他所有的判...
-
卡其色卫衣配什么裤子(卡其色卫衣的多种搭配方式)
卡其色卫衣是现代休闲装中的一种经典款式,不仅舒适实用,还充满了时尚感。然而,很多人却不知道该如何搭配裤子,以突出卡其色卫衣的特色。...
-
windows系统用苹果鼠标(如何在Windows系统中使用苹果鼠标)
如何在Windows系统中使用苹果鼠标?在日常使用中,很多人可能会遇到这样的问题:手头只有一只苹果鼠标,但使用的电脑却是Windo...