jackson json序列化實現(xiàn)首字母大寫,第二個字母需小寫
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);
}
可實際運行后,結(jié)果與希望不一樣:
org.junit.ComparisonFailure:
Expected :{"BName":"234234"}
Actual :{"Bname":"234234"}
jackson在序列化時把第二個大寫字母n轉(zhuǎn)成了小寫,這是為什么呢?
以下是跟蹤源碼的過程:
直接找到:com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector#collectAll這個方法:

執(zhí)行完_addFields(props)方法后:

執(zhí)行完_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;
}
根據(jù)stdNaming來決定這個name是以什么標準輸出,默認的是false;
stdManglePropertyName 就是原始輸出。
legacyManglePropertyName 就是規(guī)范輸出。
下面的代碼就是規(guī)范輸出:
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循環(huán)中,去除set后,第一個字母小寫,
第二字母小寫后,與第二個字母比較,如果都是小寫,則直接接上,返回,
如果第二字母大寫,就如我們的這種情況,就以小寫的情況,接上,再去找下一個字母,直到找到小寫字母為止。
意思就是為了滿足駝峰命名規(guī)則,要規(guī)范輸出。
如果我們的字段命名正如它的規(guī)范的話,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這條,

其實在是這里把第一條刪除了。因為:

這些屬性為空,導(dǎo)致這個字段不可見:
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;
}
測試結(jié)果如下:
org.junit.ComparisonFailure:
Expected :{"BName":"234234"}
Actual :{"Bname":"234234","BName":"234234"}
雖然生成了BName,但是Bname仍在(加了JsonProperty就visable了)。
第二個就是配置
objectMapper的MapperFeature.USE_STD_BEAN_NAMIN如上文提到了,非規(guī)范化輸出。
如下代碼:
@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;
// 反序列化時調(diào)用
@Override
public String nameForSetterMethod(MapperConfig<?> config,
AnnotatedMethod method, String defaultName) {
return method.getName().substring(3);
}
// 序列化時調(diào)用
@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的配置,要注意對其他功能的影響。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot實現(xiàn)發(fā)送郵件任務(wù)
這篇文章主要為大家詳細介紹了SpringBoot實現(xiàn)發(fā)送郵件任務(wù),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-02-02
Java設(shè)計模塊系列之書店管理系統(tǒng)單機版(二)
這篇文章主要為大家詳細介紹了Java單機版的書店管理系統(tǒng)設(shè)計模塊和思想第二章,感興趣的小伙伴們可以參考一下2016-08-08
詳談@Cacheable不起作用的原因:bean未序列化問題
這篇文章主要介紹了@Cacheable不起作用的原因:bean未序列化問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01
Spring的Bean注入解析結(jié)果BeanDefinition詳解
這篇文章主要介紹了Spring的Bean注入解析結(jié)果BeanDefinition詳解,BeanDefinition描述了一個bean實例,擁有屬性值、構(gòu)造參數(shù)值和具體實現(xiàn)的其他信息,其是一個bean的元數(shù)據(jù),xml中配置的bean元素會被解析成BeanDefinition對象,需要的朋友可以參考下2023-12-12
Spring?Boot?實現(xiàn)Redis分布式鎖原理
這篇文章主要介紹了Spring?Boot實現(xiàn)Redis分布式鎖原理,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的朋友可以參考一下2022-08-08

