用了几年的 Fastjson,我最终替换成了Jackson!
共 21538字,需浏览 44分钟
·
2021-05-10 19:10
点击上方“码农突围”,马上关注 这里是码农充电第一站,回复“666”,获取一份专属大礼包 真爱,请设置“星标”或点个“在看”
为什么要替换fastjson
fastjson太过于侧重性能,对于部分高级特性支持不够,而且部分自定义特性完全偏离了json和js规范导致和其他框架不兼容;
fastjson文档缺失较多,部分Feature甚至没有文档,而且代码缺少注释较为晦涩;
fastjson的CVE bug监测较弱,很多CVE数据库网站上有关fastjson的CVE寥寥无几,例如近期的AutoType导致的高危漏洞,虽然和Jackson的PolymorphicDeserialization是同样的bug,但是CVE网站上几乎没有fastjson的bug报告。
框架选型
jackson2(com.fasterxml.jackson)
gson
org.json
jackson1(com.codehuas.jackson)
fastjson
cheshire
json-simple
jackson vs gson
JSON in Java
the ultimate json library json-simple vs gson vs jackson vs json
jackson-datatype-commons-lang3
,以及更丰富的输出数据格式支持例如jackson-dataformat-yaml
,而且spring框架默认使用jackson,因此最终我选择使用jackson。替换fastjson
JSONObject
和JSONArray
实例的相关操作。fastjson v1.2.60
jackson-core v2.9.9
jackson-annotations v2.9.0
jackson-databind v2.9.9.3
Deserialization
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);
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;
}
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;
}
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的反序列化特性对照表
Serialization
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);
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();
}
}
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);
}
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的序列化特性对照表
Annotation
@JSONPOJOBuilder
@JsonPOJOBuilder
。@JSONCreator
@JsonCreator
。@JSONField
@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
@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
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
的过渡方法#
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。
https://github.com/larva-zhang/jackson-datatype-fastjson
JSONPath#
JacksonJsonProvider
替代json-path/JsonPath默认的JsonSmartJsonProvider
即可。自定义扩展
自定义Deserializer
ObjectDeserializer
接口的deserialze
方法<T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName);
StdDeserializer
抽象类,重写deserialize
方法public abstract T deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException;
自定义Serializer
ObjectSerializer
接口的write
方法void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException;
StdSerializer
抽象类,重写serialize
方法public abstract void serialize(T value, JsonGenerator gen, SerializerProvider serializers) throws IOException;
自定义Serialize Filter
SerializeFilter
,详见fastjson/wiki/SerializeFilter。而在jackson中则是建议继承
SimpleBeanPropertyFilter
。https://github.com/alibaba/fastjson/wiki/SerializeFilter
参考文档
alibaba/fastjson
FasterXML/jackson
Jackson快速替换Fastjson之道
fastjson Features 说明
fastjson SerializerFeatures 说明
fastjson JSONField 说明
Jackson – Decide What Fields Get Serialized/Deserialized
- END - 最近热文
• 尼玛,Github上最邪恶的开源项目了!未满18或者女孩子勿进哦~ • 永别了,91网站!宣布永久关闭 • 腾讯员工晒出薪资:真实 985 毕业薪资,大家看我还有救吗?网友:日薪? • 再见深圳!我要去成都搞IT了!