乐趣区

关于java:用了几年的-Fastjson我最终替换成了Jackson

作者:larva-zhh\
起源:www.cnblogs.com/larva-zhh/p/11544317.html

为什么要替换 fastjson

工程里大量应用了 fastjson 作为序列化和反序列化框架,甚至 ORM 在解决局部字段也依赖 fastjson 进行序列化和反序列化。那么作为大量应用的根底框架,为什么还要进行替换呢?

起因有以下几点:

  1. fastjson 太过于偏重性能,对于局部高级个性反对不够,而且局部自定义个性齐全偏离了 json 和 js 标准导致和其余框架不兼容;
  2. fastjson 文档缺失较多,局部 Feature 甚至没有文档,而且代码短少正文较为艰涩;
  3. 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/…,成果尚待察看。

替换 fastjson

fastjson 常见的应用场景就是序列化和反序列化,偶然会有 JSONObjectJSONArray实例的相干操作。

以下步骤的源码剖析基于以下版本:

  • 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 的静态方法 (JSONObjectJSONArray的静态方法也是来自于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 = (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.000Z2018-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 不反对该个性,然而能够通过 @JsonSetternulls()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.classabstract classesinterfaces 属性的 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 的静态方法 (JSONObjectJSONArray的静态方法也是来自于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 中 JSONObjectJSONArray的源码:

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 呈现大量批改,因为短少了JSONObjectJSONArray提供的多种便当的类型转换办法。如果想要临时保留 JSONObjectJSONArray,此时能够采取一种取巧的办法。

临时保留 JSONObject & JSONArray 的过渡办法

jackson 官网提供了对 org.json 库的数据类型反对 jackson-datatype-json-org,因而能够将com.alibaba.fastjson.JSONObject 替换为 org.json.JSONObjectcom.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 开发手册(嵩山版)》最新公布,速速下载!

感觉不错,别忘了顺手点赞 + 转发哦!

退出移动版