Jackson!超好用~
不點(diǎn)藍(lán)字,我們哪來(lái)故事?

每天 11 點(diǎn)更新文章,餓了點(diǎn)外賣,點(diǎn)擊 ??《無(wú)門(mén)檻外賣優(yōu)惠券,每天免費(fèi)領(lǐng)!》

來(lái)源:cnblogs.com/larva-zhh/p/11544317.html
為什么要替換fastjson 框架選型 替換fastjson Deserialization Serialization Annotation JSONObject&JSONArrayJSONPath 自定義擴(kuò)展

為什么要替換fastjson
工程里大量使用了fastjson作為序列化和反序列化框架,甚至ORM在處理部分字段也依賴fastjson進(jìn)行序列化和反序列化。那么作為大量使用的基礎(chǔ)框架,為什么還要進(jìn)行替換呢?
原因有以下幾點(diǎn):
fastjson太過(guò)于側(cè)重性能,對(duì)于部分高級(jí)特性支持不夠,而且部分自定義特性完全偏離了json和js規(guī)范導(dǎo)致和其他框架不兼容; fastjson文檔缺失較多,部分Feature甚至沒(méi)有文檔,而且代碼缺少注釋較為晦澀; fastjson的CVE bug監(jiān)測(cè)較弱,很多CVE數(shù)據(jù)庫(kù)網(wǎng)站上有關(guān)fastjson的CVE寥寥無(wú)幾,例如近期的AutoType導(dǎo)致的高危漏洞,雖然和Jackson的PolymorphicDeserialization是同樣的bug,但是CVE網(wǎng)站上幾乎沒(méi)有fastjson的bug報(bào)告。
框架選型
參考mvnrepository json libraries,根據(jù)流行度排序后前十名框架:
jackson2(com.fasterxml.jackson) gson org.json jackson1(com.codehuas.jackson) fastjson cheshire json-simple

jackson1是已經(jīng)過(guò)時(shí)的框架,因此可以忽略,cheshire和json-simple排名尚且不如fastjson,也忽略,剩余jackson2、gson以及org.json,其中org.json的使用量(usage)遠(yuǎn)小于jackson2(方便起見(jiàn),下文均以jackson均指代jackson2)和gson,因此org.json也可以排除了。
關(guān)于jackson和gson的比較文章有很多,stackoverflow上自行搜索,下面僅推薦幾篇blog:
jackson vs gson JSON in Java the ultimate json library json-simple vs gson vs jackson vs json
在功能特性支持、穩(wěn)定性、可擴(kuò)展性、易用性以及社區(qū)活躍度上 jackson 和 gson 差不多,入門(mén)教程可以分別參考baeldung jackson系列 以及 baeldung gson系列。但是jackson有更多現(xiàn)成的類庫(kù)兼容支持例如jackson-datatype-commons-lang3,以及更豐富的輸出數(shù)據(jù)格式支持例如jackson-dataformat-yaml,而且spring框架默認(rèn)使用jackson,因此最終我選擇使用jackson。
PS: Jackson 2.10.0開(kāi)始嘗試基于新的API使用白名單機(jī)制來(lái)避免RCE漏洞,詳見(jiàn)https://github.com/FasterXML/jackson-databind/issues/2195,效果尚待觀察。
替換fastjson
fastjson常見(jiàn)的使用場(chǎng)景就是序列化和反序列化,偶爾會(huì)有JSONObject和JSONArray實(shí)例的相關(guān)操作。
以下步驟的源碼分析基于以下版本:
fastjson v1.2.60jackson-core v2.9.9jackson-annotations v2.9.0jackson-databind v2.9.9.3
Deserialization
fastjson將json字符串反序列化成Java Bean通常使用com.alibaba.fastjson.JSON的靜態(tài)方法(JSONObject和JSONArray的靜態(tài)方法也是來(lái)自于JSON),常用的有以下幾個(gè)API:
public static JSONObject parseObject(String text);
public static JSONObject parseObject(String text, Feature... features);
public static <T> T parseObject(String text, Class<T> clazz);
public static <T> T parseObject(String text, Class<T> clazz, Feature... features);
public static <T> T parseObject(String text, TypeReference<T> type, Feature... features);
public static JSONArray parseArray(String text);
public static <T> List<T> parseArray(String text, Class<T> clazz);
從方法入?yún)⒕湍懿碌?,fastjson在執(zhí)行反序列化時(shí)的Parse行為由com.alibaba.fastjson.parser.Feature指定。研究parseObject的源碼后,發(fā)現(xiàn)底層最終都是使用的以下方法:
public static <T> T parseObject(String input, Type clazz, ParserConfig config, ParseProcess processor, int featureValues, Feature... features) {
if (input == null) {
return null;
}
// featureValues作為基準(zhǔn)解析特性開(kāi)關(guān)值
// 入?yún)eatures和featureValues取并集得到最終的解析特性
if (features != null) {
for (Feature feature : features) {
featureValues |= feature.mask;
}
}
DefaultJSONParser parser = new DefaultJSONParser(input, config, featureValues);
if (processor != null) {
if (processor instanceof ExtraTypeProvider) {
parser.getExtraTypeProviders().add((ExtraTypeProvider) processor);
}
if (processor instanceof ExtraProcessor) {
parser.getExtraProcessors().add((ExtraProcessor) processor);
}
if (processor instanceof FieldTypeResolver) {
parser.setFieldTypeResolver((FieldTypeResolver) processor);
}
}
T value = (T) parser.parseObject(clazz, null);
parser.handleResovleTask(value);
parser.close();
return (T) value;
}
通過(guò)IDE搜索usage后,發(fā)現(xiàn)當(dāng)沒(méi)有作為基準(zhǔn)解析特性開(kāi)關(guān)的featureValues入?yún)r(shí),都是使用的DEFAULT_PARSE_FEATURE作為基準(zhǔn)解析特性開(kāi)關(guān),以下是JSON.DEFAULT_PARSE_FEATURE的實(shí)例化代碼:
static {
int features = 0;
features |= Feature.AutoCloseSource.getMask();
features |= Feature.InternFieldNames.getMask();
features |= Feature.UseBigDecimal.getMask();
features |= Feature.AllowUnQuotedFieldNames.getMask();
features |= Feature.AllowSingleQuotes.getMask();
features |= Feature.AllowArbitraryCommas.getMask();
features |= Feature.SortFeidFastMatch.getMask();
features |= Feature.IgnoreNotMatch.getMask();
DEFAULT_PARSER_FEATURE = features;
}
fastjson還會(huì)從環(huán)境變量中讀取配置來(lái)修改DEFAULT_PARSER_FEATURE(雖然很少會(huì)有人這么做),但最好還是通過(guò)實(shí)際運(yùn)行一下程序來(lái)確認(rèn)你的環(huán)境中的實(shí)際解析特性開(kāi)關(guān)。
@Test
public void printFastJsonDefaultParserFeature() {
for (Feature feature : Feature.values()) {
if (Feature.isEnabled(JSON.DEFAULT_PARSER_FEATURE, feature)) {
System.out.println(feature);
}
}
}
fastjson 和 jackson的反序列化特性對(duì)照表
| fastjson特性說(shuō)明 | fastjson枚舉 | fastjson默認(rèn)狀態(tài) | jackson枚舉 | jackson默認(rèn)狀態(tài) | jackson特性說(shuō)明 |
|---|---|---|---|---|---|
| Parser close時(shí)自動(dòng)關(guān)閉為創(chuàng)建Parser實(shí)例而創(chuàng)建的底層InputStream以及Reader等輸入流 | Feature.AutoCloseSource | 開(kāi)啟 | JsonParser.Feature.AUTO_CLOSE_SOURCE | 開(kāi)啟 | 保持開(kāi)啟 |
| 允許json字符串中帶注釋 | Feature.AllowComment | 關(guān)閉 | JsonParser.Feature.ALLOW_COMMENTS | 關(guān)閉 | 根據(jù)系統(tǒng)的json數(shù)據(jù)情況開(kāi)啟 |
| 允許json字段名不被引號(hào)包括起來(lái) | Feature.AllowUnQuotedFieldNames | 開(kāi)啟 | JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES | 關(guān)閉 | 根據(jù)系統(tǒng)的json數(shù)據(jù)情況開(kāi)啟 |
| 允許json字段名使用單引號(hào)包括起來(lái) | Feature.AllowSingleQuotes | 開(kāi)啟 | JsonParser.Feature.ALLOW_SINGLE_QUOTES | 關(guān)閉 | 根據(jù)系統(tǒng)的json數(shù)據(jù)情況開(kāi)啟 |
將json字段名作為字面量緩存起來(lái),即fieldName.intern() | Feature.InternFieldNames | 開(kāi)啟 | - | - | jackson默認(rèn)使用InternCache緩存了PropertyName |
識(shí)別ISO8601格式的日期字符串,例如:2018-05-31T19:13:42.000Z或2018-05-31T19:13:42.000+07:00 | Feature.AllowISO8601DateFormat | 關(guān)閉 | - | - | jackson默認(rèn)支持ISO8601格式日期字符串的解析,并且也可以通過(guò)ObjectMapper.setDateFormat指定解析格式 |
| 忽略json中包含的連續(xù)的多個(gè)逗號(hào),非標(biāo)準(zhǔn)特性 | Feature.AllowArbitraryCommas | 關(guān)閉 | - | - | jackson不支持該特性,且該特性是非標(biāo)準(zhǔn)特性,因此可以忽略 |
| 將json中的浮點(diǎn)數(shù)解析成BigDecimal對(duì)象,禁用后會(huì)解析成Double對(duì)象 | Feature.UseBigDecimal | 開(kāi)啟 | DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS | 關(guān)閉 | 建議開(kāi)啟 |
| 解析時(shí)忽略未知的字段繼續(xù)完成解析 | Feature.IgnoreNotMatch | 開(kāi)啟 | DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES | 開(kāi)啟 | jackson默認(rèn)開(kāi)啟遇到未知屬性需要拋異常,因此如要和fastjson保持一致則需要關(guān)閉該特性 |
| 如果你用fastjson序列化的文本,輸出的結(jié)果是按照f(shuō)ieldName排序輸出的,parser時(shí)也能利用這個(gè)順序進(jìn)行優(yōu)化讀取。這種情況下,parser能夠獲得非常好的性能 | Feature.SortFeidFastMatch | 關(guān)閉 | - | - | fastjson內(nèi)部處理邏輯,jackson不支持該特性,不影響功能 |
| 禁用ASM | Feature.DisableASM | 關(guān)閉 | - | - | fastjson內(nèi)部處理邏輯,jackson不支持該特性,不影響功能 |
| 禁用循環(huán)引用檢測(cè) | Feature.DisableCircularReferenceDetect | 關(guān)閉 | - | - | fastjson內(nèi)部處理邏輯,jackson不支持該特性,不影響功能 |
| 對(duì)于沒(méi)有值的字符串屬性設(shè)置為空串 | Feature.InitStringFieldAsEmpty | 關(guān)閉 | - | - | jackson不支持該特性,但是可以通過(guò)@JsonSetter的nulls()和contentNulls()分別設(shè)置Bean以及Array/Collection的元素對(duì)null的處理方式。例如Nulls.AS_EMPTY就會(huì)將null設(shè)置為JsonDeserializer.getEmptyValue |
非標(biāo)準(zhǔn)特性,允許將數(shù)組按照字段順序解析成Java Bean,例如"[1001,\"xx\",33]"可以等價(jià)為"{\"id\": 10001, \"name\": \"xx\", \"age\": 33}" | Feature.SupportArrayToBean | 關(guān)閉 | - | - | 非標(biāo)準(zhǔn)特性,且使用場(chǎng)景較少,jackson不支持該特性 |
| 解析后屬性保持原來(lái)的順序 | Feature.OrderedField | 關(guān)閉 | - | - | - |
| 禁用特殊字符檢查 | Feature.DisableSpecialKeyDetect | 關(guān)閉 | - | - | - |
| 使用對(duì)象數(shù)組而不是集合 | Feature.UseObjectArray | 關(guān)閉 | DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY | 關(guān)閉 | 保持關(guān)閉 |
| 支持解析沒(méi)有setter方法的非public屬性 | Feature.SupportNonPublicField | 關(guān)閉 | - | - | jaskson可以通過(guò)ObjectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)來(lái)達(dá)到相同的目的 |
禁用fastjson的AUTOTYPE特性,即不按照json字符串中的@type自動(dòng)選擇反序列化類 | Feature.IgnoreAutoType | 關(guān)閉 | - | - | jackson的PolymorphicDeserialization默認(rèn)是支持Object.class、abstract classes、interfaces屬性的AUTO Type,但是該特性容易導(dǎo)致安全漏洞,強(qiáng)烈建議使用ObjectMapper.disableDefaultTyping()設(shè)置為只允許@JsonTypeInfo生效 |
| 禁用屬性智能匹配,例如下劃線自動(dòng)匹配駝峰等 | Feature.DisableFieldSmartMatch | 關(guān)閉 | - | - | jackson可以通過(guò)ObjectMapper.setPropertyNamingStrategy()達(dá)到相同的目的,但這種是針對(duì)一個(gè)json串的統(tǒng)一策略,如果要在一個(gè)json串中使用不同的策略則可以使用@JsonProperty.value()指定字段名 |
啟用fastjson的autotype功能,即根據(jù)json字符串中的@type自動(dòng)選擇反序列化的類 | Feature.SupportAutoType | 關(guān)閉 | ObjectMapper.DefaultTyping.* | 開(kāi)啟 | jackson的PolymorphicDeserialization支持不同級(jí)別的AUTO TYPE,但是這個(gè)功能容易導(dǎo)致安全漏洞,強(qiáng)烈建議使用ObjectMapper.disableDefaultTyping()設(shè)置為只允許@JsonTypeInfo生效 |
解析時(shí)將未用引號(hào)包含的json字段名作為String類型存儲(chǔ),否則只能用原始類型獲取key的值。例如String text="{123:\"abc\"}"在啟用了NonStringKeyAsString后可以通過(guò)JSON.parseObject(text).getString("123")的方式獲取到"abc",而在不啟用NonStringKeyAsString時(shí),JSON.parseObject(text).getString("123")只能得到null,必須通過(guò)JSON.parseObject(text).get(123)的方式才能獲取到"abc"。 | Feature.NonStringKeyAsString | 關(guān)閉 | - | - | 非標(biāo)準(zhǔn)特性,jackson并不支持 |
自定義"{\"key\":value}"解析成Map實(shí)例,否則解析為JSONObject | Feature.CustomMapDeserializer | 關(guān)閉 | - | - | jackson沒(méi)有相應(yīng)的全局特性,但是可以通過(guò)TypeReference達(dá)到相同的效果 |
枚舉未匹配到時(shí)拋出異常,否則解析為null | Feature.ErrorOnEnumNotMatch | 關(guān)閉 | DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL | 關(guān)閉 | fastjson默認(rèn)解析為null,jackson則相反,默認(rèn)會(huì)拋異常,建議采用jackson默認(rèn)行為 |
反序列化fastjson和jackson的特性TestCase見(jiàn)DeserializationUseJacksonReplaceFastJsonTest.java
Serialization
fastjson將Java Bean序列化成json字符串通常也是使用com.alibaba.fastjson.JSON的靜態(tài)方法(JSONObject和JSONArray的靜態(tài)方法也是來(lái)自于JSON),常用的有以下幾個(gè)API:
public static String toJSONString(Object object);
public static String toJSONString(Object object, SerializerFeature... features);
public static String toJSONStringWithDateFormat(Object object, String dateFormat, SerializerFeature... features);
public static String toJSONString(Object object, boolean prettyFormat);
public static void writeJSONString(Writer writer, Object object, SerializerFeature... features);
從方法入?yún)⒁材芸闯觯谛蛄谢瘯r(shí),fastjson的特性由SerializerFeature控制,研究toJSONString的源碼后,發(fā)現(xiàn)最終都會(huì)調(diào)用以下方法:
public static String toJSONString(Object object, SerializeConfig config, SerializeFilter[] filters, String dateFormat, int defaultFeatures, SerializerFeature... features) {
SerializeWriter out = new SerializeWriter(null, defaultFeatures, features);
try {
JSONSerializer serializer = new JSONSerializer(out, config);
if (dateFormat != null && dateFormat.length() != 0) {
serializer.setDateFormat(dateFormat);
serializer.config(SerializerFeature.WriteDateUseDateFormat, true);
}
if (filters != null) {
for (SerializeFilter filter : filters) {
serializer.addFilter(filter);
}
}
serializer.write(object);
return out.toString();
} finally {
out.close();
}
}
通過(guò)IDE搜索usage后,發(fā)現(xiàn)當(dāng)沒(méi)有作為基準(zhǔn)解析特性開(kāi)關(guān)的defaultFeatures入?yún)r(shí),都是使用的DEFAULT_GENERATE_FEATURE作為基準(zhǔn)解析特性開(kāi)關(guān),以下是JSON.DEFAULT_GENERATE_FEATURE的實(shí)例化代碼:
static {
int features = 0;
features |= SerializerFeature.QuoteFieldNames.getMask();
features |= SerializerFeature.SkipTransientField.getMask();
features |= SerializerFeature.WriteEnumUsingName.getMask();
features |= SerializerFeature.SortField.getMask();
DEFAULT_GENERATE_FEATURE = features;
config(IOUtils.DEFAULT_PROPERTIES);
}
fastjson還會(huì)從環(huán)境變量中讀取配置來(lái)修改DEFAULT_GENERATE_FEATURE(雖然很少會(huì)有人這么做),但最好還是通過(guò)實(shí)際運(yùn)行一下程序來(lái)確認(rèn)你的環(huán)境中的實(shí)際解析特性開(kāi)關(guān)。
@Test
public void printFastJsonDefaultGenerateFeature() {
for (SerializerFeature feature : SerializerFeature.values()) {
if (SerializerFeature.isEnabled(JSON.DEFAULT_GENERATE_FEATURE, feature)) {
System.out.println(feature);
}
}
}
fastjson 和 jackson的序列化特性對(duì)照表
| fastjson特性說(shuō)明 | fastjson枚舉 | fastjson默認(rèn)狀態(tài) | jackson枚舉 | jackson默認(rèn)狀態(tài) | jackson特性說(shuō)明 |
|---|---|---|---|---|---|
| 輸出的json字段名被引號(hào)包含 | SerializerFeature.QuoteFieldNames | 開(kāi)啟 | JsonGenerator.Feature.QUOTE_FIELD_NAMES | 開(kāi)啟 | 保持開(kāi)啟 |
| 序列化時(shí)使用單引號(hào),而不是使用雙引號(hào) | SerializerFeature.UseSingleQuotes | 關(guān)閉 | - | - | jackson不支持該特性 |
序列化時(shí),value為null的key或field也輸出 | SerializerFeature.WriteMapNullValue | 關(guān)閉 | JsonInclude.Include.ALWAYS | 開(kāi)啟 | 建議按需選擇。注意SerializationFeature.WRITE_NULL_MAP_VALUES從2.9已廢棄,且會(huì)被JsonInclude.Include給覆蓋 |
序列化枚舉時(shí)使用枚舉類型的toString()方法,和SerializerFeature.WriteEnumUsingName互斥 | SerializerFeature.WriteEnumUsingToString | 關(guān)閉 | SerializationFeature.WRITE_ENUMS_USING_TO_STRING | 關(guān)閉 | 建議關(guān)閉,或者和反序列化的DeserializationFeature.READ_ENUMS_USING_TO_STRING保持一致 |
序列化枚舉時(shí)使用枚舉類型的name()方法,和SerializerFeature.WriteEnumUsingToString互斥 | SerializerFeature.WriteEnumUsingName | 開(kāi)啟 | - | - | jackson的默認(rèn)行為,無(wú)需配置 |
| 序列化時(shí)對(duì)Date、Calendar等類型使用ISO8601格式進(jìn)行格式化,否則以timestamp形式輸出Long數(shù)字 | SerializerFeature.UseISO8601DateFormat | 關(guān)閉 | SerializationFeature.WRITE_DATES_AS_TIMESTAMPS | 開(kāi)啟 | jackson和fastjson的默認(rèn)行為都是將Date數(shù)據(jù)輸出為L(zhǎng)ong,建議根據(jù)不同的場(chǎng)景選擇是否需要格式化日期 |
序列化List類型數(shù)據(jù)時(shí)將null輸出為"[]" | SerializerFeature.WriteNullListAsEmpty | 關(guān)閉 | - | - | 可以通過(guò)PropertyFilter/SerializerFactory.withSerializerModifier(BeanSerializerModifier)任一一種方式達(dá)到相同效果,推薦使用PropertyFilter |
序列化String類型的field時(shí)將null輸出為"" | SerializerFeature.WriteNullStringAsEmpty | 關(guān)閉 | - | - | 可以通過(guò)PropertyFilter/SerializerFactory.withSerializerModifier(BeanSerializerModifier)任一一種方式達(dá)到相同效果,推薦使用PropertyFilter |
序列化Number類型的field時(shí)將null輸出為0 | SerializerFeature.WriteNullNumberAsZero | 關(guān)閉 | - | - | 可以通過(guò)PropertyFilter/SerializerFactory.withSerializerModifier(BeanSerializerModifier)任一一種方式達(dá)到相同效果,推薦使用PropertyFilter |
序列化Boolean類型的field時(shí)將null輸出為false | SerializerFeature.WriteNullBooleanAsFalse | 關(guān)閉 | - | - | 可以通過(guò)PropertyFilter/SerializerFactory.withSerializerModifier(BeanSerializerModifier)任一一種方式達(dá)到相同效果,推薦使用PropertyFilter |
序列化時(shí)忽略transient修飾的field | SerializerFeature.SkipTransientField | 開(kāi)啟 | MapperFeature.PROPAGATE_TRANSIENT_MARKER | 關(guān)閉 | 建議保持關(guān)閉,通過(guò)@JsonIgnore或者FilterProvider來(lái)指定忽略的屬性 |
序列化時(shí),如果未指定order,則將field按照getter方法的字典順序排序 | SerializerFeature.SortField | 開(kāi)啟 | MapperFeature.SORT_PROPERTIES_ALPHABETICALLY | 關(guān)閉 | 建議關(guān)閉,排序會(huì)影響序列化性能(fastjson在反序列化時(shí)支持按照f(shuō)ield順序讀取解析,因此排序后的json串有利于提高fastjson的解析性能,但jackson并沒(méi)有該特性) |
把\t做轉(zhuǎn)義輸出,已廢棄,即使開(kāi)啟也無(wú)效 | SerializerFeature.WriteTabAsSpecial | 關(guān)閉 | - | - | - |
| 格式化json輸出 | SerializerFeature.PrettyFormat | 關(guān)閉 | SerializationFeature.INDENT_OUTPUT | 關(guān)閉 | 建議保持關(guān)閉,格式化可以交給前端完成 |
| 序列化時(shí)把類型名稱寫(xiě)入json | SerializerFeature.WriteClassName | 關(guān)閉 | - | - | jackson可以通過(guò)@JsonTypeInfo達(dá)到類似的效果,參見(jiàn)Jackson Annotation Examples |
| 序列化時(shí)消除對(duì)同一對(duì)象循環(huán)引用的問(wèn)題 | SerializerFeature.DisableCircularReferenceDetect | 關(guān)閉 | SerializationFeature.FAIL_ON_SELF_REFERENCES | 開(kāi)啟 | 保持開(kāi)啟,避免循環(huán)引用 |
| 對(duì)斜杠'/'進(jìn)行轉(zhuǎn)義 | SerializerFeature.WriteSlashAsSpecial | 關(guān)閉 | - | - | jackson可以通過(guò)自定義Serializer實(shí)現(xiàn)相同效果,按需設(shè)置 |
將中文都會(huì)序列化為\uXXXX格式,字節(jié)數(shù)會(huì)多一些,但是能兼容IE 6 | SerializerFeature.BrowserCompatible | 關(guān)閉 | - | - | jackson可以通過(guò)自定義Serializer實(shí)現(xiàn)相同效果,按需設(shè)置 |
全局修改日期格式,默認(rèn)使用JSON.DEFFAULT_DATE_FORMAT | SerializerFeature.WriteDateUseDateFormat | 關(guān)閉 | - | - | jackson可以通過(guò)@JsonFormat.pattern()、ObjectMapper.setDateFormat()等方式實(shí)現(xiàn)相同效果 |
| 序列化時(shí)不把最外層的類型名稱寫(xiě)入json | SerializerFeature.NotWriteRootClassName | 關(guān)閉 | - | - | jackson可以通過(guò)@JsonRootName達(dá)到類似的效果,參見(jiàn)Jackson Annotation Examples |
| 不轉(zhuǎn)義特殊字符,已廢棄,即使開(kāi)啟也無(wú)效 | SerializerFeature.DisableCheckSpecialChar | 關(guān)閉 | - | - | - |
將Bean序列化時(shí)將field值按順序當(dāng)成json數(shù)組輸出,而不是json object,同時(shí)不會(huì)輸出fieldName,例如:{"id":123,"name":"xxx"}會(huì)輸出成[123,"xxx"] | SerializerFeature.BeanToArray | 關(guān)閉 | - | - | 非標(biāo)準(zhǔn)特性,jackson并不支持 |
序列化Map時(shí)將非String類型的key作為String類型輸出,例如:{123:231}會(huì)輸出成{"123":231} | SerializerFeature.WriteNonStringKeyAsString | 關(guān)閉 | - | - | 非標(biāo)準(zhǔn)特性,jackson并不支持 |
序列化Byte、Short、Integer、Long、Float、Double、Boolean及其對(duì)應(yīng)原始類型field時(shí),如果屬性值為各自類型的默認(rèn)值(如0、0F、0L),則不會(huì)輸出該屬性 | SerializerFeature.NotWriteDefaultValue | 關(guān)閉 | - | - | 非標(biāo)準(zhǔn)特性,jackson并不支持 |
序列化時(shí)將(、)、>、<以u(píng)nicode編碼輸出 | SerializerFeature.BrowserSecure | 關(guān)閉 | - | - | jackson可以通過(guò)自定義Serializer實(shí)現(xiàn)相同效果,按需設(shè)置,通??梢越唤o前端處理 |
| 序列化時(shí)忽略沒(méi)有實(shí)際屬性對(duì)應(yīng)的getter方法 | SerializerFeature.IgnoreNonFieldGetter | 關(guān)閉 | - | - | - |
| 序列化時(shí)把非String類型數(shù)據(jù)當(dāng)作String類型輸出 | SerializerFeature.WriteNonStringValueAsString | 關(guān)閉 | - | - | jackson有一個(gè)類似的特性JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS可以將數(shù)字作為字符串輸出,但沒(méi)有覆蓋所有非String類型 |
| 序列化時(shí)忽略會(huì)拋異常的getter方法 | SerializerFeature.IgnoreErrorGetter | 關(guān)閉 | - | - | - |
| 序列化時(shí)將BigDecimal使用toPlainString()輸出 | SerializerFeature.WriteBigDecimalAsPlain | 關(guān)閉 | JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN | 關(guān)閉 | 按需開(kāi)啟 |
| 序列化時(shí)對(duì)Map按照Key進(jìn)行排序 | SerializerFeature.MapSortField | 關(guān)閉 | SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS | 關(guān)閉 | 建議關(guān)閉,開(kāi)啟會(huì)影響性能 |
序列化fastjson和jackson的特性TestCase見(jiàn)SerializationUseJacksonReplaceFastJsonTest.java
Annotation
fastjsonzhu相對(duì)于jackson來(lái)說(shuō)注解的功能劃分的并沒(méi)有那么細(xì),因此fastjson的一個(gè)注解可能等價(jià)于jackson多個(gè)注解的組合。
@JSONPOJOBuilder
指定反序列化時(shí)創(chuàng)建java對(duì)象使用的build方法,對(duì)應(yīng)jackson的@JsonPOJOBuilder。
@JSONCreator
指定反序列化時(shí)創(chuàng)建java對(duì)象使用的構(gòu)造方法,對(duì)應(yīng)jackson的@JsonCreator。
@JSONField
指定序列化和反序列化field時(shí)的行為。反序列化時(shí),等價(jià)于@JsonProperty + @JsonDeserialize + @JsonUnwrapped + @JsonFormat+ @JsonAlias;序列化時(shí),等價(jià)于@JsonProperty + @JsonSerialize + @JsonUnwrapped + @JsonFormat + @JsonRawValue + @JsonView。
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER })
public @interface JSONField {
// 序列化和反序列化時(shí)的字段順序,等價(jià)于jackson的@JsonProperty.index()
int ordinal() default 0;
// 序列化和反序列化時(shí)的字段名稱映射,等價(jià)于jackson的@JsonProperty.value()
String name() default "";
// 序列化和反序列化時(shí)的數(shù)據(jù)格式(日期格式、16進(jìn)制等等),等價(jià)于jackson的@JsonFormat.shape() + @JsonFormat.pattern()
String format() default "";
// 字段是否序列化,等價(jià)于jackson的@JsonProperty.access()
boolean serialize() default true;
// 字段是否反序列化,等價(jià)于jackson的@JsonProperty.access()
boolean deserialize() default true;
// 序列化特性,等價(jià)于jackson的@JsonProperty.with()
SerializerFeature[] serialzeFeatures() default {};
// 反序列化特性,等價(jià)于jackson的@JsonFormat.with()
Feature[] parseFeatures() default {};
// 對(duì)屬性進(jìn)行打標(biāo),便于在序列化時(shí)進(jìn)行exclude或include,等價(jià)于jackson的@JsonView
String label() default "";
// 序列化時(shí)將字段內(nèi)容直接輸出,不經(jīng)過(guò)轉(zhuǎn)義,等價(jià)于jackson的@JsonRawValue
boolean jsonDirect() default false;
// 指定序列化時(shí)使用的Serializer Class,等價(jià)于jackson的@JsonSerialize
Class<?> serializeUsing() default Void.class;
// 指定反序列化時(shí)使用的Deserializer Class,等價(jià)于jackson的@JsonDeserialize
Class<?> deserializeUsing() default Void.class;
// 指定反序列化時(shí)使用的字段別名,等價(jià)于jackson的@JsonAlias
String[] alternateNames() default {};
// 將字段的子屬性映射到父節(jié)點(diǎn)上,等價(jià)于jackson的@JsonUnwrapped
boolean unwrapped() default false;
// 指定序列化時(shí)字段為null時(shí)使用的默認(rèn)值,等價(jià)于jackson的@JsonProperty.defaultValue()
String defaultValue() default "";
}
unwrapped的用法可以參考AnnotationUseJacksonReplaceFastJsonTest.java中的testJSONFieldUnwrapped。
@JSONType
指定序列化和反序列化一個(gè)Java Bean時(shí)的行為。
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
public @interface JSONType {
// 是否使用asm優(yōu)化,jackson無(wú)對(duì)應(yīng)特性
boolean asm() default true;
// 序列化和反序列化時(shí)的field排序,等價(jià)于jackson的@JsonPropertyOrder.value()
String[] orders() default {};
// 序列化和反序列化時(shí)包含的field,等價(jià)于jackson的
String[] includes() default {};
// 序列化和反序列化時(shí)忽略的field,等價(jià)于jackson的@JsonIgnoreProperties
String[] ignores() default {};
// 序列化特性,等價(jià)于jackson的@JsonProperty.with()
SerializerFeature[] serialzeFeatures() default {};
// 反序列化特性,等價(jià)于jackson的@JsonFormat.with()
Feature[] parseFeatures() default {};
// 序列化時(shí)是否依據(jù)field字母順序排序,等價(jià)于jackson的@JsonPropertyOrder.alphabetic()
boolean alphabetic() default true;
// 反序列化多態(tài)類型時(shí),如果根據(jù)其他typeName等方式無(wú)法找到正確的子類時(shí),默認(rèn)使用的子類,等價(jià)于jackson的@JsonTypeInfo.defaultImpl()
Class<?> mappingTo() default Void.class;
// 反序列化時(shí)指定java bean builder類(必須是@JSONPOJOBuilder注解的類),等價(jià)于jackson的@JsonDeserialize.builder()
Class<?> builder() default Void.class;
// 聲明這個(gè)類型的別名,反序列化多態(tài)類型時(shí)使用,等價(jià)于jackson的@JsonTypeName
String typeName() default "";
// 反序列化某個(gè)接口或抽象類或父類的子類時(shí)指定根據(jù)哪個(gè)字段的值和子類的typeName相等來(lái)決定具體實(shí)現(xiàn)類,等價(jià)于jackson的@JsonTypeInfo.use() = Id.CUSTOM + @JsonTypeInfo.property()
String typeKey() default "";
// 反序列化某個(gè)接口或抽象類或父類的子類時(shí)指定可以反序列化的子類類型,等價(jià)于jackson的@JsonSubTypes
Class<?>[] seeAlso() default{};
// 指定序列化時(shí)使用的Serializer Class,等價(jià)于jackson的@JsonSerialize
Class<?> serializer() default Void.class;
// 指定反序列化時(shí)使用的Deserializer Class,等價(jià)于jackson的@JsonDeserialize
Class<?> deserializer() default Void.class;
// 序列化時(shí),如果filed是枚舉類型,則和普通的java bean一樣輸出枚舉的filed,而不是通常使用的Enum.name()值,jackson沒(méi)有對(duì)應(yīng)特性
boolean serializeEnumAsJavaBean() default false;
// 指定json和Java bean之間的字段名稱映射策略,等價(jià)于jackson的@JsonNaming
PropertyNamingStrategy naming() default PropertyNamingStrategy.CamelCase;
// 指定序列化時(shí)使用的Serialize filter,等價(jià)于jackson的@JsonFilter
Class<? extends SerializeFilter>[] serialzeFilters() default {};
}
JSONObject & JSONArray
首先來(lái)看看fastjon中JSONObject和JSONArray的源碼:
public class JSONObject extends JSON implements Map<String, Object>, Cloneable, Serializable, InvocationHandler {
private final Map<String, Object> map;
...
}
public class JSONArray extends JSON implements List<Object>, Cloneable, RandomAccess, Serializable {
private static final long serialVersionUID = 1L;
private final List<Object> list;
protected transient Object relatedArray;
protected transient Type componentType;
...
}
從源碼就可以發(fā)現(xiàn),JSONObject實(shí)際是一個(gè)Map<String, Object>,而JSONArray實(shí)際是一個(gè)List<JSONObject>。因此可以將JSONObject類型改為Map<String, Object>,而JSONArray類型改為List<Object>。但是這種方式就會(huì)導(dǎo)致上層API出現(xiàn)大量修改,因?yàn)槿鄙倭?code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">JSONObject和JSONArray提供的多種便利的類型轉(zhuǎn)換方法。如果想要暫時(shí)保留JSONObject和JSONArray,此時(shí)可以采取一種取巧的方法。
暫時(shí)保留JSONObject & JSONArray的過(guò)渡方法
jackson官方提供了對(duì)org.json庫(kù)的數(shù)據(jù)類型支持jackson-datatype-json-org,因此可以將com.alibaba.fastjson.JSONObject替換為org.json.JSONObject,com.alibaba.fastjson.JSONArray替換為org.json.JSONArray,這兩個(gè)類庫(kù)的對(duì)象API大致相同,當(dāng)然一些細(xì)小的改動(dòng)還是避免不了的。如果想完全不改上層代碼,那也可以參考jackson-datatype-json-org和jackson-datatype-json-lib自己實(shí)現(xiàn)jackson對(duì)fastjson的數(shù)據(jù)類型的binder。
larva-zhang/jackson-datatype-fastjson歡迎大家使用或提issues。
JSONPath
使用json-path/JsonPath就能輕松替換fastjson的JSONPath,而且功能比f(wàn)astjson更強(qiáng)大。只需參考JsonProvider SPI使用JacksonJsonProvider替代json-path/JsonPath默認(rèn)的JsonSmartJsonProvider即可。
自定義擴(kuò)展
自定義Deserializer
fastjson中實(shí)現(xiàn)自定義Deserializer的方法通常是實(shí)現(xiàn)ObjectDeserializer接口的deserialze方法
<T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName);
在jackson中實(shí)現(xiàn)自定義Serializer的方法則通常是繼承StdDeserializer抽象類,重寫(xiě)deserialize方法
public abstract T deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException;
自定義Serializer
fastjson中實(shí)現(xiàn)自定義Serializer的方法通常是實(shí)現(xiàn)ObjectSerializer接口的write方法
void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException;
在jackson中實(shí)現(xiàn)自定義Serializer的方法則通常是繼承StdSerializer抽象類,重寫(xiě)serialize方法
public abstract void serialize(T value, JsonGenerator gen, SerializerProvider serializers) throws IOException;
自定義Serialize Filter
fastjson中提供了6種SerializeFilter,詳見(jiàn)fastjson/wiki/SerializeFilter。而在jackson中則是建議繼承SimpleBeanPropertyFilter。
往期推薦
下方二維碼關(guān)注我

技術(shù)草根,堅(jiān)持分享 編程,算法,架構(gòu)

看完文章,餓了點(diǎn)外賣,點(diǎn)擊 ??《無(wú)門(mén)檻外賣優(yōu)惠券,每天免費(fèi)領(lǐng)!》

