概述
gson和jackson在使用上是很相似的,不論是直接和POJO互相轉換,還是逐個屬性解析Json文本,基本上沒有什麼差別。
但是由於對屬性名解析策略上有所不同,在遇到isXxx或者hasXxx形式的getter方法時就有差別了。
對於isXxx形式,gson生成的json會是isXxx或者is_xxx形式;而jackson生成的會是xxx形式,也就是自動刪除了is。
對於hasXxx形式,gson生成的是xxx形式;而jackson會忽略掉這個屬性,因爲jackson只識別getXxx和isXxx形式的getter方法。
如果,希望jackson能夠識別hasXxx形式,那麼需要給它加上@JsonProperty(“hasXxx”)註解。
當然了,一般情況下,我們用eclipse自帶的getter、setter創建工具,是不會出現hasXXX這樣的getter方法的。
jackson想指定屬性名字轉換成json的樣式可以這樣做:
1.使用@JsonProperty註解,指定字段名;
2.給ObjectMapper指定PropertyNamingStrategy,這種方式可以生成駝峯式、小寫+橫線連字符式、小寫+下劃線連字符式等多種形式;
3.使用自定義的PropertyNamingStrategy實現字段名轉換。
@JsonProperty註解方式
需要在特殊的字段上都加上註解:
@JsonProperty("hasChecked")
private boolean hasChecked;
@JsonProperty("isMyFault")
private boolean isMyFault;
指定PropertyNamingStrategy
jackson默認輸出的是駝峯形式字段名,可以通過指定PropertyNamingStrategy,輸出小寫+橫線連字符式、小寫+下劃線連字符式的字段名:
mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
使用自定義的PropertyNamingStrategy
上邊說到了從gson轉到jackson時,isXxx類型的字段名輸出不一致。
如果恰好你們的項目裏面也遇到這樣的問題,可以用@JsonProperty的方式明確指定字段名,如果字段多的話就是稍微麻煩點,問題也不大。
但是如果像我們的項目一樣,就慘了,我們系統提供pc的spring mvc服務,你知道spring mvc默認使用的是jackson返回json數據的。
然而,我們的項目同時提供內部使用的rest接口,接口返回的json是用gson返回的(自己封裝了一個netty框架)。數據Model共享,導致同一個字段在pc端返回的需要是駝峯形式,在內部rest接口返回小寫+下劃線方式。
可想而知,用@JsonProperty是不行的了,不能做到兩方兼顧。
這時候就可以使用第三種方式,自定義PropertyNamingStrategy來實現了:
mapper.setPropertyNamingStrategy(new PropertyNamingStrategy() {
@Override
public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) {
String input = defaultName;
if(method.getName().startsWith("is")){
input = method.getName();
}
if (input == null) return input;
int length = input.length();
StringBuilder result = new StringBuilder(length * 2);
int resultLength = 0;
boolean wasPrevTranslated = false;
for (int i = 0; i < length; i++)
{
char c = input.charAt(i);
if (i > 0 || c != '_') // skip first starting underscore
{
if (Character.isUpperCase(c))
{
if (!wasPrevTranslated && resultLength > 0 && result.charAt(resultLength - 1) != '_')
{
result.append('_');
resultLength++;
}
c = Character.toLowerCase(c);
wasPrevTranslated = true;
}
else
{
wasPrevTranslated = false;
}
result.append(c);
resultLength++;
}
}
return resultLength > 0 ? result.toString() : input;
}
});
20170825補充
現實場景一般來說會複雜一些,我們遇到的情況如下:
public class EclipseAutoMethodName {
private boolean isOutlets;
private boolean overSea;
public boolean isOutlets() {
return isOutlets;
}
public void setOutlets(boolean isOutlets) {
this.isOutlets = isOutlets;
}
public boolean isOverSea() {
return overSea;
}
public void setOverSea(boolean overSea) {
this.overSea = overSea;
}
}
其中的getter和setter方法都是eclipse自動生成的,gson的處理方法是field優先。它會解析成:
{"isOutlets":true,"overSea":false}
jackson不指定PropertyNamingStrategy的情況下會解析成:
{"outlets":true,"overSea":false}
也就是,會自動擦除is。
如果使用本文中給的PropertyNamingStrategy實現,那麼會被jackson解析成:
{"isOutlets":true,"isOverSea":false}
因爲jackson是Getter方法優先,所以,如果你的歷史代碼中有這種字段名以is開頭,也有非is開頭的boolean屬性的時候,唯一的處理方法就是把以is開頭的boolean屬性的getter方法前加get,如下:
public class EclipseAutoMethodName {
private boolean isOutlets;
private boolean overSea;
public boolean getIsOutlets() {
return isOutlets;
}
public void setOutlets(boolean isOutlets) {
this.isOutlets = isOutlets;
}
public boolean isOverSea() {
return overSea;
}
public void setOverSea(boolean overSea) {
this.overSea = overSea;
}
}