作者: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/…,成果尚待察看。
替换 fastjson
fastjson 常见的应用场景就是序列化和反序列化,偶然会有 JSONObject
和JSONArray
实例的相干操作。
以下步骤的源码剖析基于以下版本:
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
的静态方法 (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 = (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 开发手册(嵩山版)》最新公布,速速下载!
感觉不错,别忘了顺手点赞 + 转发哦!