作者:larva-zhh
來源:www.cnblogs.com/larva-zhh/p/11544317.html
為什么要替換fastjson
工程里大量使用了fastjson作為序列化和反序列化框架,甚至ORM在處理部分欄位也依賴fastjson進行序列化和反序列化,那么作為大量使用的基礎框架,為什么還要進行替換呢?
原因有以下幾點:
- fastjson太過于側重性能,對于部分高級特性支持不夠,而且部分自定義特性完全偏離了json和js規范導致和其他框架不兼容;
- fastjson檔案缺失較多,部分Feature甚至沒有檔案,而且代碼缺少注釋較為晦澀;
- fastjson的CVE bug監測較弱,很多CVE資料庫網站上有關fastjson的CVE寥寥無幾,例如近期的AutoType導致的高危漏洞,雖然和Jackson的PolymorphicDeserialization是同樣的bug,但是CVE網站上幾乎沒有fastjson的bug報告,
框架選型
參考mvnrepository json libraries,根據流行度排序后前十名框架:
- jackson2(com.fasterxml.jackson)
- gson
- org.json
- jackson1(com.codehuas.jackson)
- fastjson
- cheshire
- json-simple

jackson1是已經過時的框架,因此可以忽略,cheshire和json-simple排名尚且不如fastjson,也忽略,剩余jackson2、gson以及org.json,其中org.json的使用量(usage)遠小于jackson2(方便起見,下文均以jackson均指代jackson2)和gson,因此org.json也可以排除了,
關于jackson和gson的比較文章有很多,stackoverflow上自行搜索,下面僅推薦幾篇blog:
- jackson vs gson
- JSON in Java
- the ultimate json library json-simple vs gson vs jackson vs json
在功能特性支持、穩定性、可擴展性、易用性以及社區活躍度上 jackson 和 gson 差不多,入門教程可以分別參考baeldung jackson系列 以及 baeldung gson系列,但是jackson有更多現成的類別庫兼容支持例如jackson-datatype-commons-lang3,以及更豐富的輸出資料格式支持例如jackson-dataformat-yaml,而且spring框架默認使用jackson,因此最終我選擇使用jackson,
PS: Jackson 2.10.0開始嘗試基于新的API使用白名單機制來避免RCE漏洞,詳見https://github.com/FasterXML/jackson-databind/issues/2195,效果尚待觀察,
替換fastjson
fastjson常見的使用場景就是序列化和反序列化,偶爾會有JSONObject和JSONArray實體的相關操作,
以下步驟的原始碼分析基于以下版本:
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的靜態方法(JSONObject和JSONArray的靜態方法也是來自于JSON),常用的有以下幾個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);
從方法入參就能猜到,fastjson在執行反序列化時的Parse行為由com.alibaba.fastjson.parser.Feature指定,研究parseObject的原始碼后,發現底層最終都是使用的以下方法:
public static <T> T parseObject(String input, Type clazz, ParserConfig config, ParseProcess processor, int featureValues, Feature... features) {
if (input == null) {
return null;
}
// featureValues作為基準決議特性開關值
// 入參features和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 = https://www.cnblogs.com/javastack/archive/2021/06/20/(T) parser.parseObject(clazz, null);
parser.handleResovleTask(value);
parser.close();
return (T) value;
}
通過IDE搜索usage后,發現當沒有作為基準決議特性開關的featureValues入參時,都是使用的DEFAULT_PARSE_FEATURE作為基準決議特性開關,以下是JSON.DEFAULT_PARSE_FEATURE的實體化代碼:
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還會從環境變數中讀取配置來修改DEFAULT_PARSER_FEATURE(雖然很少會有人這么做),但最好還是通過實際運行一下程式來確認你的環境中的實際決議特性開關,
@Test
public void printFastJsonDefaultParserFeature() {
for (Feature feature : Feature.values()) {
if (Feature.isEnabled(JSON.DEFAULT_PARSER_FEATURE, feature)) {
System.out.println(feature);
}
}
}
fastjson 和 jackson的反序列化特性對照表
| fastjson特性說明 | fastjson列舉 | fastjson默認狀態 | jackson列舉 | jackson默認狀態 | jackson特性說明 |
|---|---|---|---|---|---|
| Parser close時自動關閉為創建Parser實體而創建的底層InputStream以及Reader等輸入流 | Feature.AutoCloseSource | 開啟 | JsonParser.Feature.AUTO_CLOSE_SOURCE | 開啟 | 保持開啟 |
| 允許json字串中帶注釋 | Feature.AllowComment | 關閉 | JsonParser.Feature.ALLOW_COMMENTS | 關閉 | 根據系統的json資料情況開啟 |
| 允許json欄位名不被引號包括起來 | Feature.AllowUnQuotedFieldNames | 開啟 | JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES | 關閉 | 根據系統的json資料情況開啟 |
| 允許json欄位名使用單引號包括起來 | Feature.AllowSingleQuotes | 開啟 | JsonParser.Feature.ALLOW_SINGLE_QUOTES | 關閉 | 根據系統的json資料情況開啟 |
將json欄位名作為字面量快取起來,即fieldName.intern() |
Feature.InternFieldNames | 開啟 | - | - | jackson默認使用InternCache快取了PropertyName |
識別ISO8601格式的日期字串,例如:2018-05-31T19:13:42.000Z或2018-05-31T19:13:42.000+07:00 |
Feature.AllowISO8601DateFormat | 關閉 | - | - | jackson默認支持ISO8601格式日期字串的決議,并且也可以通過ObjectMapper.setDateFormat指定決議格式 |
| 忽略json中包含的連續的多個逗號,非標準特性 | Feature.AllowArbitraryCommas | 關閉 | - | - | jackson不支持該特性,且該特性是非標準特性,因此可以忽略 |
| 將json中的浮點數決議成BigDecimal物件,禁用后會決議成Double物件 | Feature.UseBigDecimal | 開啟 | DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS | 關閉 | 建議開啟 |
| 決議時忽略未知的欄位繼續完成決議 | Feature.IgnoreNotMatch | 開啟 | DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES | 開啟 | jackson默認開啟遇到未知屬性需要拋例外,因此如要和fastjson保持一致則需要關閉該特性 |
| 如果你用fastjson序列化的文本,輸出的結果是按照fieldName排序輸出的,parser時也能利用這個順序進行優化讀取,這種情況下,parser能夠獲得非常好的性能 | Feature.SortFeidFastMatch | 關閉 | - | - | fastjson內部處理邏輯,jackson不支持該特性,不影響功能 |
| 禁用ASM | Feature.DisableASM | 關閉 | - | - | fastjson內部處理邏輯,jackson不支持該特性,不影響功能 |
| 禁用回圈參考檢測 | Feature.DisableCircularReferenceDetect | 關閉 | - | - | fastjson內部處理邏輯,jackson不支持該特性,不影響功能 |
| 對于沒有值的字串屬性設定為空串 | Feature.InitStringFieldAsEmpty | 關閉 | - | - | jackson不支持該特性,但是可以通過@JsonSetter的nulls()和contentNulls()分別設定Bean以及Array/Collection的元素對null的處理方式,例如Nulls.AS_EMPTY就會將null設定為JsonDeserializer.getEmptyValue |
非標準特性,允許將陣列按照欄位順序決議成Java Bean,例如"[1001,\"xx\",33]"可以等價為"{\"id\": 10001, \"name\": \"xx\", \"age\": 33}" |
Feature.SupportArrayToBean | 關閉 | - | - | 非標準特性,且使用場景較少,jackson不支持該特性 |
| 決議后屬性保持原來的順序 | Feature.OrderedField | 關閉 | - | - | - |
| 禁用特殊字符檢查 | Feature.DisableSpecialKeyDetect | 關閉 | - | - | - |
| 使用物件陣列而不是集合 | Feature.UseObjectArray | 關閉 | DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY | 關閉 | 保持關閉 |
| 支持決議沒有setter方法的非public屬性 | Feature.SupportNonPublicField | 關閉 | - | - | jaskson可以通過ObjectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)來達到相同的目的 |
禁用fastjson的AUTOTYPE特性,即不按照json字串中的@type自動選擇反序列化類 |
Feature.IgnoreAutoType | 關閉 | - | - | jackson的PolymorphicDeserialization默認是支持Object.class、abstract classes、interfaces屬性的AUTO Type,但是該特性容易導致安全漏洞,強烈建議使用ObjectMapper.disableDefaultTyping()設定為只允許@JsonTypeInfo生效 |
| 禁用屬性智能匹配,例如下劃線自動匹配駝峰等 | Feature.DisableFieldSmartMatch | 關閉 | - | - | jackson可以通過ObjectMapper.setPropertyNamingStrategy()達到相同的目的,但這種是針對一個json串的統一策略,如果要在一個json串中使用不同的策略則可以使用@JsonProperty.value()指定欄位名 |
啟用fastjson的autotype功能,即根據json字串中的@type自動選擇反序列化的類 |
Feature.SupportAutoType | 關閉 | ObjectMapper.DefaultTyping.* | 開啟 | jackson的PolymorphicDeserialization支持不同級別的AUTO TYPE,但是這個功能容易導致安全漏洞,強烈建議使用ObjectMapper.disableDefaultTyping()設定為只允許@JsonTypeInfo生效 |
決議時將未用引號包含的json欄位名作為String型別存盤,否則只能用原始型別獲取key的值,例如String text="{123:\"abc\"}"在啟用了NonStringKeyAsString后可以通過JSON.parseObject(text).getString("123")的方式獲取到"abc",而在不啟用NonStringKeyAsString時,JSON.parseObject(text).getString("123")只能得到null,必須通過JSON.parseObject(text).get(123)的方式才能獲取到"abc", |
Feature.NonStringKeyAsString | 關閉 | - | - | 非標準特性,jackson并不支持 |
自定義"{\"key\":value}"決議成Map實體,否則決議為JSONObject |
Feature.CustomMapDeserializer | 關閉 | - | - | jackson沒有相應的全域特性,但是可以通過TypeReference達到相同的效果 |
列舉未匹配到時拋出例外,否則決議為null |
Feature.ErrorOnEnumNotMatch | 關閉 | DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL | 關閉 | fastjson默認決議為null,jackson則相反,默認會拋例外,建議采用jackson默認行為 |
反序列化fastjson和jackson的特性TestCase見DeserializationUseJacksonReplaceFastJsonTest.java
Serialization
fastjson將Java Bean序列化成json字串通常也是使用com.alibaba.fastjson.JSON的靜態方法(JSONObject和JSONArray的靜態方法也是來自于JSON),常用的有以下幾個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);
從方法入參也能看出,在序列化時,fastjson的特性由SerializerFeature控制,研究toJSONString的原始碼后,發現最終都會呼叫以下方法:
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();
}
}
通過IDE搜索usage后,發現當沒有作為基準決議特性開關的defaultFeatures入參時,都是使用的DEFAULT_GENERATE_FEATURE作為基準決議特性開關,以下是JSON.DEFAULT_GENERATE_FEATURE的實體化代碼:
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還會從環境變數中讀取配置來修改DEFAULT_GENERATE_FEATURE(雖然很少會有人這么做),但最好還是通過實際運行一下程式來確認你的環境中的實際決議特性開關,
@Test
public void printFastJsonDefaultGenerateFeature() {
for (SerializerFeature feature : SerializerFeature.values()) {
if (SerializerFeature.isEnabled(JSON.DEFAULT_GENERATE_FEATURE, feature)) {
System.out.println(feature);
}
}
}
fastjson 和 jackson的序列化特性對照表
| fastjson特性說明 | fastjson列舉 | fastjson默認狀態 | jackson列舉 | jackson默認狀態 | jackson特性說明 |
|---|---|---|---|---|---|
| 輸出的json欄位名被引號包含 | SerializerFeature.QuoteFieldNames | 開啟 | JsonGenerator.Feature.QUOTE_FIELD_NAMES | 開啟 | 保持開啟 |
| 序列化時使用單引號,而不是使用雙引號 | SerializerFeature.UseSingleQuotes | 關閉 | - | - | jackson不支持該特性 |
序列化時,value為null的key或field也輸出 |
SerializerFeature.WriteMapNullValue | 關閉 | JsonInclude.Include.ALWAYS | 開啟 | 建議按需選擇,注意SerializationFeature.WRITE_NULL_MAP_VALUES從2.9已廢棄,且會被JsonInclude.Include給覆寫 |
序列化列舉時使用列舉型別的toString()方法,和SerializerFeature.WriteEnumUsingName互斥 |
SerializerFeature.WriteEnumUsingToString | 關閉 | SerializationFeature.WRITE_ENUMS_USING_TO_STRING | 關閉 | 建議關閉,或者和反序列化的DeserializationFeature.READ_ENUMS_USING_TO_STRING保持一致 |
序列化列舉時使用列舉型別的name()方法,和SerializerFeature.WriteEnumUsingToString互斥 |
SerializerFeature.WriteEnumUsingName | 開啟 | - | - | jackson的默認行為,無需配置 |
| 序列化時對Date、Calendar等型別使用ISO8601格式進行格式化,否則以timestamp形式輸出Long數字 | SerializerFeature.UseISO8601DateFormat | 關閉 | SerializationFeature.WRITE_DATES_AS_TIMESTAMPS | 開啟 | jackson和fastjson的默認行為都是將Date資料輸出為Long,建議根據不同的場景選擇是否需要格式化日期 |
序列化List型別資料時將null輸出為"[]" |
SerializerFeature.WriteNullListAsEmpty | 關閉 | - | - | 可以通過PropertyFilter/SerializerFactory.withSerializerModifier(BeanSerializerModifier)任一一種方式達到相同效果,推薦使用PropertyFilter |
序列化String型別的field時將null輸出為"" |
SerializerFeature.WriteNullStringAsEmpty | 關閉 | - | - | 可以通過PropertyFilter/SerializerFactory.withSerializerModifier(BeanSerializerModifier)任一一種方式達到相同效果,推薦使用PropertyFilter |
序列化Number型別的field時將null輸出為0 |
SerializerFeature.WriteNullNumberAsZero | 關閉 | - | - | 可以通過PropertyFilter/SerializerFactory.withSerializerModifier(BeanSerializerModifier)任一一種方式達到相同效果,推薦使用PropertyFilter |
序列化Boolean型別的field時將null輸出為false |
SerializerFeature.WriteNullBooleanAsFalse | 關閉 | - | - | 可以通過PropertyFilter/SerializerFactory.withSerializerModifier(BeanSerializerModifier)任一一種方式達到相同效果,推薦使用PropertyFilter |
序列化時忽略transient修飾的field |
SerializerFeature.SkipTransientField | 開啟 | MapperFeature.PROPAGATE_TRANSIENT_MARKER | 關閉 | 建議保持關閉,通過@JsonIgnore或者FilterProvider來指定忽略的屬性 |
序列化時,如果未指定order,則將field按照getter方法的字典順序排序 |
SerializerFeature.SortField | 開啟 | MapperFeature.SORT_PROPERTIES_ALPHABETICALLY | 關閉 | 建議關閉,排序會影響序列化性能(fastjson在反序列化時支持按照field順序讀取決議,因此排序后的json串有利于提高fastjson的決議性能,但jackson并沒有該特性) |
把\t做轉義輸出,已廢棄,即使開啟也無效 |
SerializerFeature.WriteTabAsSpecial | 關閉 | - | - | - |
| 格式化json輸出 | SerializerFeature.PrettyFormat | 關閉 | SerializationFeature.INDENT_OUTPUT | 關閉 | 建議保持關閉,格式化可以交給前端完成 |
| 序列化時把型別名稱寫入json | SerializerFeature.WriteClassName | 關閉 | - | - | jackson可以通過@JsonTypeInfo達到類似的效果,參見Jackson Annotation Examples |
| 序列化時消除對同一物件回圈參考的問題 | SerializerFeature.DisableCircularReferenceDetect | 關閉 | SerializationFeature.FAIL_ON_SELF_REFERENCES | 開啟 | 保持開啟,避免回圈參考 |
| 對斜杠'/'進行轉義 | SerializerFeature.WriteSlashAsSpecial | 關閉 | - | - | jackson可以通過自定義Serializer實作相同效果,按需設定 |
將中文都會序列化為\uXXXX格式,位元組數會多一些,但是能兼容IE 6 |
SerializerFeature.BrowserCompatible | 關閉 | - | - | jackson可以通過自定義Serializer實作相同效果,按需設定 |
全域修改日期格式,默認使用JSON.DEFFAULT_DATE_FORMAT |
SerializerFeature.WriteDateUseDateFormat | 關閉 | - | - | jackson可以通過@JsonFormat.pattern()、ObjectMapper.setDateFormat()等方式實作相同效果 |
| 序列化時不把最外層的型別名稱寫入json | SerializerFeature.NotWriteRootClassName | 關閉 | - | - | jackson可以通過@JsonRootName達到類似的效果,參見Jackson Annotation Examples |
| 不轉義特殊字符,已廢棄,即使開啟也無效 | SerializerFeature.DisableCheckSpecialChar | 關閉 | - | - | - |
將Bean序列化時將field值按順序當成json陣列輸出,而不是json object,同時不會輸出fieldName,例如:{"id":123,"name":"xxx"}會輸出成[123,"xxx"] |
SerializerFeature.BeanToArray | 關閉 | - | - | 非標準特性,jackson并不支持 |
序列化Map時將非String型別的key作為String型別輸出,例如:{123:231}會輸出成{"123":231} |
SerializerFeature.WriteNonStringKeyAsString | 關閉 | - | - | 非標準特性,jackson并不支持 |
序列化Byte、Short、Integer、Long、Float、Double、Boolean及其對應原始型別field時,如果屬性值為各自型別的默認值(如0、0F、0L),則不會輸出該屬性 |
SerializerFeature.NotWriteDefaultValue | 關閉 | - | - | 非標準特性,jackson并不支持 |
序列化時將(、)、>、<以unicode編碼輸出 |
SerializerFeature.BrowserSecure | 關閉 | - | - | jackson可以通過自定義Serializer實作相同效果,按需設定,通常可以交給前端處理 |
| 序列化時忽略沒有實際屬性對應的getter方法 | SerializerFeature.IgnoreNonFieldGetter | 關閉 | - | - | - |
| 序列化時把非String型別資料當作String型別輸出 | SerializerFeature.WriteNonStringValueAsString | 關閉 | - | - | jackson有一個類似的特性JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS可以將數字作為字串輸出,但沒有覆寫所有非String型別 |
| 序列化時忽略會拋例外的getter方法 | SerializerFeature.IgnoreErrorGetter | 關閉 | - | - | - |
| 序列化時將BigDecimal使用toPlainString()輸出 | SerializerFeature.WriteBigDecimalAsPlain | 關閉 | JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN | 關閉 | 按需開啟 |
| 序列化時對Map按照Key進行排序 | SerializerFeature.MapSortField | 關閉 | SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS | 關閉 | 建議關閉,開啟會影響性能 |
序列化fastjson和jackson的特性TestCase見SerializationUseJacksonReplaceFastJsonTest.java
Annotation
fastjsonzhu相對于jackson來說注解的功能劃分的并沒有那么細,因此fastjson的一個注解可能等價于jackson多個注解的組合,
@JSONPOJOBuilder
指定反序列化時創建java物件使用的build方法,對應jackson的@JsonPOJOBuilder,
@JSONCreator
指定反序列化時創建java物件使用的構造方法,對應jackson的@JsonCreator,
@JSONField
指定序列化和反序列化field時的行為,反序列化時,等價于@JsonProperty + @JsonDeserialize + @JsonUnwrapped + @JsonFormat+ @JsonAlias;序列化時,等價于@JsonProperty + @JsonSerialize + @JsonUnwrapped + @JsonFormat + @JsonRawValue + @JsonView,
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER })
public @interface JSONField {
// 序列化和反序列化時的欄位順序,等價于jackson的@JsonProperty.index()
int ordinal() default 0;
// 序列化和反序列化時的欄位名稱映射,等價于jackson的@JsonProperty.value()
String name() default "";
// 序列化和反序列化時的資料格式(日期格式、16進制等等),等價于jackson的@JsonFormat.shape() + @JsonFormat.pattern()
String format() default "";
// 欄位是否序列化,等價于jackson的@JsonProperty.access()
boolean serialize() default true;
// 欄位是否反序列化,等價于jackson的@JsonProperty.access()
boolean deserialize() default true;
// 序列化特性,等價于jackson的@JsonProperty.with()
SerializerFeature[] serialzeFeatures() default {};
// 反序列化特性,等價于jackson的@JsonFormat.with()
Feature[] parseFeatures() default {};
// 對屬性進行打標,便于在序列化時進行exclude或include,等價于jackson的@JsonView
String label() default "";
// 序列化時將欄位內容直接輸出,不經過轉義,等價于jackson的@JsonRawValue
boolean jsonDirect() default false;
// 指定序列化時使用的Serializer Class,等價于jackson的@JsonSerialize
Class<?> serializeUsing() default Void.class;
// 指定反序列化時使用的Deserializer Class,等價于jackson的@JsonDeserialize
Class<?> deserializeUsing() default Void.class;
// 指定反序列化時使用的欄位別名,等價于jackson的@JsonAlias
String[] alternateNames() default {};
// 將欄位的子屬性映射到父節點上,等價于jackson的@JsonUnwrapped
boolean unwrapped() default false;
// 指定序列化時欄位為null時使用的默認值,等價于jackson的@JsonProperty.defaultValue()
String defaultValue() default "";
}
unwrapped的用法可以參考AnnotationUseJacksonReplaceFastJsonTest.java中的testJSONFieldUnwrapped,
@JSONType
指定序列化和反序列化一個Java Bean時的行為,
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
public @interface JSONType {
// 是否使用asm優化,jackson無對應特性
boolean asm() default true;
// 序列化和反序列化時的field排序,等價于jackson的@JsonPropertyOrder.value()
String[] orders() default {};
// 序列化和反序列化時包含的field,等價于jackson的
String[] includes() default {};
// 序列化和反序列化時忽略的field,等價于jackson的@JsonIgnoreProperties
String[] ignores() default {};
// 序列化特性,等價于jackson的@JsonProperty.with()
SerializerFeature[] serialzeFeatures() default {};
// 反序列化特性,等價于jackson的@JsonFormat.with()
Feature[] parseFeatures() default {};
// 序列化時是否依據field字母順序排序,等價于jackson的@JsonPropertyOrder.alphabetic()
boolean alphabetic() default true;
// 反序列化多型型別時,如果根據其他typeName等方式無法找到正確的子類時,默認使用的子類,等價于jackson的@JsonTypeInfo.defaultImpl()
Class<?> mappingTo() default Void.class;
// 反序列化時指定java bean builder類(必須是@JSONPOJOBuilder注解的類),等價于jackson的@JsonDeserialize.builder()
Class<?> builder() default Void.class;
// 宣告這個型別的別名,反序列化多型型別時使用,等價于jackson的@JsonTypeName
String typeName() default "";
// 反序列化某個介面或抽象類或父類的子類時指定根據哪個欄位的值和子類的typeName相等來決定具體實作類,等價于jackson的@JsonTypeInfo.use() = Id.CUSTOM + @JsonTypeInfo.property()
String typeKey() default "";
// 反序列化某個介面或抽象類或父類的子類時指定可以反序列化的子型別別,等價于jackson的@JsonSubTypes
Class<?>[] seeAlso() default{};
// 指定序列化時使用的Serializer Class,等價于jackson的@JsonSerialize
Class<?> serializer() default Void.class;
// 指定反序列化時使用的Deserializer Class,等價于jackson的@JsonDeserialize
Class<?> deserializer() default Void.class;
// 序列化時,如果filed是列舉型別,則和普通的java bean一樣輸出列舉的filed,而不是通常使用的Enum.name()值,jackson沒有對應特性
boolean serializeEnumAsJavaBean() default false;
// 指定json和Java bean之間的欄位名稱映射策略,等價于jackson的@JsonNaming
PropertyNamingStrategy naming() default PropertyNamingStrategy.CamelCase;
// 指定序列化時使用的Serialize filter,等價于jackson的@JsonFilter
Class<? extends SerializeFilter>[] serialzeFilters() default {};
}
JSONObject & JSONArray
首先來看看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;
...
}
從原始碼就可以發現,JSONObject實際是一個Map<String, Object>,而JSONArray實際是一個List<JSONObject>,因此可以將JSONObject型別改為Map<String, Object>,而JSONArray型別改為List<Object>,但是這種方式就會導致上層API出現大量修改,因為缺少了JSONObject和JSONArray提供的多種便利的型別轉換方法,如果想要暫時保留JSONObject和JSONArray,此時可以采取一種取巧的方法,
暫時保留JSONObject & JSONArray的過渡方法
jackson官方提供了對org.json庫的資料型別支持jackson-datatype-json-org,因此可以將com.alibaba.fastjson.JSONObject替換為org.json.JSONObject,com.alibaba.fastjson.JSONArray替換為org.json.JSONArray,這兩個類別庫的物件API大致相同,當然一些細小的改動還是避免不了的,如果想完全不改上層代碼,那也可以參考jackson-datatype-json-org和jackson-datatype-json-lib自己實作jackson對fastjson的資料型別的binder,
larva-zhang/jackson-datatype-fastjson歡迎大家使用或提issues,
JSONPath
使用json-path/JsonPath就能輕松替換fastjson的JSONPath,而且功能比fastjson更強大,只需參考JsonProvider SPI使用JacksonJsonProvider替代json-path/JsonPath默認的JsonSmartJsonProvider即可,
自定義擴展
自定義Deserializer
fastjson中實作自定義Deserializer的方法通常是實作ObjectDeserializer介面的deserialze方法
<T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName);
在jackson中實作自定義Serializer的方法則通常是繼承StdDeserializer抽象類,重寫deserialize方法
public abstract T deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException;
自定義Serializer
fastjson中實作自定義Serializer的方法通常是實作ObjectSerializer介面的write方法
void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException;
在jackson中實作自定義Serializer的方法則通常是繼承StdSerializer抽象類,重寫serialize方法
public abstract void serialize(T value, JsonGenerator gen, SerializerProvider serializers) throws IOException;
自定義Serialize Filter
fastjson中提供了6種SerializeFilter,詳見fastjson/wiki/SerializeFilter,而在jackson中則是建議繼承SimpleBeanPropertyFilter,
近期熱文推薦:
1.1,000+ 道 Java面試題及答案整理(2021最新版)
2.終于靠開源專案弄到 IntelliJ IDEA 激活碼了,真香!
3.阿里 Mock 工具正式開源,干掉市面上所有 Mock 工具!
4.Spring Cloud 2020.0.0 正式發布,全新顛覆性版本!
5.《Java開發手冊(嵩山版)》最新發布,速速下載!
覺得不錯,別忘了隨手點贊+轉發哦!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/288188.html
標籤:其他
上一篇:python實戰技巧之兩個字典,如何實作鍵同則值相加【不等長或等長】
下一篇:我愛學英語系列叢筆記
