1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Jackson!超好用~

        共 28780字,需瀏覽 58分鐘

         ·

        2021-03-31 11:16

        不點(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 & JSONArray
          • JSONPath
          • 自定義擴(kuò)展

        為什么要替換fastjson

        工程里大量使用了fastjson作為序列化和反序列化框架,甚至ORM在處理部分字段也依賴fastjson進(jìn)行序列化和反序列化。那么作為大量使用的基礎(chǔ)框架,為什么還要進(jìn)行替換呢?

        原因有以下幾點(diǎn):

        1. fastjson太過(guò)于側(cè)重性能,對(duì)于部分高級(jí)特性支持不夠,而且部分自定義特性完全偏離了json和js規(guī)范導(dǎo)致和其他框架不兼容;
        2. fastjson文檔缺失較多,部分Feature甚至沒(méi)有文檔,而且代碼缺少注釋較為晦澀;
        3. 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ì)有JSONObjectJSONArray實(shí)例的相關(guān)操作。

        以下步驟的源碼分析基于以下版本:

        • fastjson v1.2.60
        • jackson-core v2.9.9
        • jackson-annotations v2.9.0
        • jackson-databind v2.9.9.3

        Deserialization

        fastjson將json字符串反序列化成Java Bean通常使用com.alibaba.fastjson.JSON的靜態(tài)方法(JSONObjectJSONArray的靜態(tài)方法也是來(lái)自于JSON),常用的有以下幾個(gè)API:

        public static JSONObject parseObject(String text);

        public static JSONObject parseObject(String text, Feature... features);

        public static <T> parseObject(String text, Class<T> clazz);

        public static <T> parseObject(String text, Class<T> clazz, Feature... features);

        public static <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> 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.000Z2018-05-31T19:13:42.000+07:00Feature.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不支持該特性,不影響功能
        禁用ASMFeature.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ò)@JsonSetternulls()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.classabstract 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í)例,否則解析為JSONObjectFeature.CustomMapDeserializer關(guān)閉--jackson沒(méi)有相應(yīng)的全局特性,但是可以通過(guò)TypeReference達(dá)到相同的效果
        枚舉未匹配到時(shí)拋出異常,否則解析為nullFeature.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)方法(JSONObjectJSONArray的靜態(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輸出為0SerializerFeature.WriteNullNumberAsZero關(guān)閉--可以通過(guò)PropertyFilter/SerializerFactory.withSerializerModifier(BeanSerializerModifier)任一一種方式達(dá)到相同效果,推薦使用PropertyFilter
        序列化Boolean類型的field時(shí)將null輸出為falseSerializerFeature.WriteNullBooleanAsFalse關(guān)閉--可以通過(guò)PropertyFilter/SerializerFactory.withSerializerModifier(BeanSerializerModifier)任一一種方式達(dá)到相同效果,推薦使用PropertyFilter
        序列化時(shí)忽略transient修飾的fieldSerializerFeature.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ě)入jsonSerializerFeature.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 6SerializerFeature.BrowserCompatible關(guān)閉--jackson可以通過(guò)自定義Serializer實(shí)現(xiàn)相同效果,按需設(shè)置
        全局修改日期格式,默認(rèn)使用JSON.DEFFAULT_DATE_FORMATSerializerFeature.WriteDateUseDateFormat關(guān)閉--jackson可以通過(guò)@JsonFormat.pattern()、ObjectMapper.setDateFormat()等方式實(shí)現(xiàn)相同效果
        序列化時(shí)不把最外層的類型名稱寫(xiě)入jsonSerializerFeature.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中JSONObjectJSONArray的源碼:

        public class JSONObject extends JSON implements Map<StringObject>, CloneableSerializableInvocationHandler {

            private final Map<String, Object> map;
            ...
        }
        public class JSONArray extends JSON implements List<Object>, CloneableRandomAccessSerializable {

            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í)保留JSONObjectJSONArray,此時(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> 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。

        往期推薦

        那些在一個(gè)公司死磕了5-10年的人,最后都怎么樣了?那些在一個(gè)公司死磕了5-10年的人,最后都怎么樣了?

        自從上了 SkyWalking,睡覺(jué)真香??!

        紅包免費(fèi)送!

        996的大公司和965的小公司,怎么選?網(wǎng)友:錢(qián)給夠就行~



        下方二維碼關(guān)注我

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

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

        朋友,助攻一把!點(diǎn)個(gè)在看!


        瀏覽 113
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            国产午夜一区二区三区 | 久久伊人777777 | 女女les互磨到高潮 | 日韩A级毛片免费视频 | 无码人妻一区二区三区 | 特色特色的欧美大片日本 | 精品国偷自产在线 | 俺去也俺就去www色情网最新更新内容 | 日韩性活大片 | 影音先锋男人色 |