1 Fastjson2简介

Fastjson2Fastjson的升级版,特征:

  • 协议支持:支持JSON/JSONB两种协议
  • 部分解析:可以使用JSONPath进行部分解析获取需要的值
  • 语言支持:Java/Kotlin
  • 场景支持:Android8+/服务端
  • 其他特性支持:Graal Native-ImageJSON Schema

2 基础使用

2.1 测试环境

环境:

  • JDK版本:1.8.0_341
  • Fastjson2版本:2.0.19

测试类:

@Builder@Data@ToStringpublic class Entity {private String field1;private Integer field2;}

2.2 JSON序列化

System.out.println(JSON.toJSONString(entity));

2.3 JSON反序列化

System.out.println(JSON.parseObject(str,Entity.class));

2.4 JSONB序列化

byte[] bytes = JSONB.toBytes(entity);

2.5 JSONB反序列化

System.out.println(JSONB.parseObject(bytes,Entity.class));

2.6 JSON Schema

JSON Schema可用于反序列化时对JSON字段进行验证使用,配置Schema可以通过@JSONField/@JSONType,这里以@JSONField为例:

public class Entity {private String field1;@JSONField(schema = "{'minimum':0,'maximum':100}")private Integer field2;}

测试代码:

Entity entity1 = Entity.builder().field2(-1).build();Entity entity2 = Entity.builder().field2(50).build();Entity entity3 = Entity.builder().field2(101).build();String str1 = JSON.toJSONString(entity1);String str2 = JSON.toJSONString(entity2);String str3 = JSON.toJSONString(entity3);try {JSON.parseObject(str1, Entity.class);} catch (Exception e) {e.printStackTrace();}JSON.parseObject(str2, Entity.class);try {JSON.parseObject(str3, Entity.class);} catch (Exception e) {e.printStackTrace();}

输出:

2.7 JSONPath

JSONPath可用于部分解析JSON字符串,示例:

Entity entity = Entity.builder().field1("a").field2(2).build();// $符号表示根对象// $.field1表示根对象的field1属性System.out.println(JSONPath.eval(entity,"$.field1"));System.out.println(JSONPath.eval(entity,"$.field2"));List<Entity> list = new ArrayList<>();list.add(Entity.builder().field1("entity1").field2(1).build());list.add(Entity.builder().field1("entity2").field2(2).build());// 如果传的是List,支持通过下标解析// 此处是返回[0,0]下标范围内的值List<Entity> names = (List<Entity>)JSONPath.eval(list,"[0,0]");System.out.println(names.get(0));

详细的解析语法以及更多例子请参考官方文档。

2.8 AutoType

AutoType是在序列化的时候带上类型的一种机制,这样在反序列化时就不需要传入类型,实现类型自动识别,例子:

Entity entity = Entity.builder().field1("a").field2(2).build();String str = JSON.toJSONString(entity, JSONWriter.Feature.WriteClassName);System.out.println(str);System.out.println(JSON.parseObject(str, Object.class, JSONReader.Feature.SupportAutoType));

输出:

由于在Fastjson1中出现过AutoType漏洞,因此官方提供了一个JVM参数完全禁止(safeMode功能):

-Dfastjson2.parser.safeMode=true

3 底层实现探究

3.1 序列化

3.1.1 概览

序列化的实现可以参考官方的一张类图:

大概流程如下:

  • 获取ObjectWriter
  • 如果从ObjectWriterProvider缓存有ObjectWriter,直接提取
  • 如果ObjectWriterProvider缓存没有ObjectWriter,构造对应的ObjectWriter,并缓存
  • 获取到ObjectWriter后,将JavaBean对象写入JSONWriter
  • JSONWriter对基础类型进行写入
  • 返回结果

3.1.2 入口

这里的序列化探究以JSON.toJSONString(Object object)作为入口:

static String toJSONString(Object object) {// 初始化ObjectWriterProviderJSONWriter.Context writeContext = new JSONWriter.Context(JSONFactory.defaultObjectWriterProvider);// 格式化控制boolean pretty = (writeContext.features & com.alibaba.fastjson2.JSONWriter.Feature.PrettyFormat.mask) != 0L;Object jsonWriter;// 默认有三个JSONWriter,JDK8一个,针对JDK9之后的byte[]实现的字符串优化也有一个,还有一个基于char[]实现的UTF16if (JDKUtils.JVM_VERSION == 8) {jsonWriter = new JSONWriterUTF16JDK8(writeContext);} else if ((writeContext.features & com.alibaba.fastjson2.JSONWriter.Feature.OptimizedForAscii.mask) != 0L) {jsonWriter = new JSONWriterUTF8JDK9(writeContext);} else {jsonWriter = new JSONWriterUTF16(writeContext);}try {// 格式化控制JSONWriter writer = pretty " />new JSONWriterPretty((JSONWriter)jsonWriter) : jsonWriter;String var12;try {if (object == null) {// null的话直接写入"null"字符串((JSONWriter)writer).writeNull();} else {// 设置根对象((JSONWriter)writer).setRootObject(object);Class<?> valueClass = object.getClass();if (valueClass == JSONObject.class) {// 如果目标类是JSNOObject,直接调用writer的write方法((JSONWriter)writer).write((JSONObject)object);} else {// 如果不是JSONWriter.Context context = ((JSONWriter)writer).context;boolean fieldBased = (context.features & com.alibaba.fastjson2.JSONWriter.Feature.FieldBased.mask) != 0L;// 通过Provider获取ObjectWriterObjectWriter<?> objectWriter = context.provider.getObjectWriter(valueClass, valueClass, fieldBased);// ObjectWriter将数据写入JSONWriterobjectWriter.write((JSONWriter)writer, object, (Object)null, (Type)null, 0L);}}// 结果var12 = writer.toString();// 下面的代码与序列化关系不大,可以不看} catch (Throwable var10) {if (writer != null) {try {((JSONWriter)writer).close();} catch (Throwable var9) {var10.addSuppressed(var9);}}throw var10;}if (writer != null) {((JSONWriter)writer).close();}return var12;} catch (NumberFormatException | NullPointerException var11) {throw new JSONException("JSON#toJSONString cannot serialize '" + object + "'", var11);}}

3.1.3 获取ObjectWriterProvider

JSON.toJSONString()入口:

JSONWriter.Context writeContext = new JSONWriter.Context(JSONFactory.defaultObjectWriterProvider);

其中会调用默认的构造方法初始化ObjectWriterProvider

public ObjectWriterProvider() {this.init();ObjectWriterCreator creator = null;switch (JSONFactory.CREATOR) {case "reflect":creator = ObjectWriterCreator.INSTANCE;break;case "lambda":creator = ObjectWriterCreatorLambda.INSTANCE;break;case "asm":default:try {creator = ObjectWriterCreatorASM.INSTANCE;} catch (Throwable var5) {}if (creator == null) {creator = ObjectWriterCreatorLambda.INSTANCE;}}this.creator = (ObjectWriterCreator)creator;}

ObjectWriterCreator采取的是单例模式,默认采用ASM动态字节码实现。

3.1.4 获取ObjectWriter

有了ObjectWriterProvider后,下一步就是获取ObjectWriter,也就是JSON.toJSONString()中的:

JSONWriter.Context context = ((JSONWriter)writer).context;boolean fieldBased = (context.features & com.alibaba.fastjson2.JSONWriter.Feature.FieldBased.mask) != 0L;ObjectWriter<?> objectWriter = context.provider.getObjectWriter(valueClass, valueClass, fieldBased);

getObjectWriter()如下:

public ObjectWriter getObjectWriter(Type objectType, Class objectClass, boolean fieldBased) {// fieldBased是基于字段序列化的意思// false的话表示基于getter序列化// 根据不同的类型从不同的缓存map中获取ObjectWriter objectWriter = fieldBased ? (ObjectWriter)this.cacheFieldBased.get(objectType) : (ObjectWriter)this.cache.get(objectType);// 首次获取应该为nullif (objectWriter != null) {return (ObjectWriter)objectWriter;} else {// 这个useModules布尔变量笔者不太了解// 这里的逻辑是 基于字段反序列化 并且 目标class不为空 并且 目标class可以赋值给Iterable 并且 目标class不能赋值给classboolean useModules = true;if (fieldBased && objectClass != null && Iterable.class.isAssignableFrom(objectClass) && !Collection.class.isAssignableFrom(objectClass)) {useModules = false;}// 这里的例子是trueif (useModules) {for(int i = 0; i < this.modules.size(); ++i) {// 获取ObjectWriterModuleObjectWriterModule module = (ObjectWriterModule)this.modules.get(i);objectWriter = module.getObjectWriter(objectType, objectClass);// 为nullif (objectWriter != null) {ObjectWriter previous = fieldBased ? (ObjectWriter)this.cacheFieldBased.putIfAbsent(objectType, objectWriter) : (ObjectWriter)this.cache.putIfAbsent(objectType, objectWriter);if (previous != null) {objectWriter = previous;}return (ObjectWriter)objectWriter;}}}// 第一次执行暂时还拿不到ObjectWriter,这里的条件全部符合if (objectWriter == null && objectClass != null && !fieldBased) {switch (objectClass.getName()) {// 针对Guava库的map内置了ObjectWritercase "com.google.common.collect.HashMultimap":case "com.google.common.collect.LinkedListMultimap":case "com.google.common.collect.LinkedHashMultimap":case "com.google.common.collect.ArrayListMultimap":case "com.google.common.collect.TreeMultimap":objectWriter = GuavaSupport.createAsMapWriter(objectClass);break;// 不是JSONObject类case "com.alibaba.fastjson.JSONObject":objectWriter = ObjectWriterImplMap.of(objectClass);}}// ObjectWriter还没拿到if (objectWriter == null) {// 第一次拿需要通过ObjectWriterCreator()去创建ObjectWriterCreator creator = this.getCreator();if (objectClass == null) {objectClass = TypeUtils.getMapping(objectType);}// 创建ObjectWriter// ObjectWriter的里面会创建FieldWriter,这里面的逻辑很长,经过一些列复杂逻辑的判断,再针对字段获取objectWriter = creator.createObjectWriter(objectClass, fieldBased ? Feature.FieldBased.mask : 0L, this);// 放入缓存ObjectWriter previous = fieldBased ? (ObjectWriter)this.cacheFieldBased.putIfAbsent(objectType, objectWriter) : (ObjectWriter)this.cache.putIfAbsent(objectType, objectWriter);if (previous != null) {objectWriter = previous;}}return (ObjectWriter)objectWriter;}}

其中FiledWriter获取逻辑如下:

// ObjectWriterCreatorASM.java 236行左右的位置BeanUtils.fields(objectClass, (field) -> {if (fieldBased || Modifier.isPublic(field.getModifiers())) {fieldInfo.init();// 创建FieldWriterFieldWriter fieldWriter = this.creteFieldWriter(objectClass, writerFeatures, provider.modules, beanInfo, fieldInfo, field);if (fieldWriter != null) {// 放入缓存fieldWriterMap.putIfAbsent(fieldWriter.fieldName, fieldWriter);}}});

3.1.5 write()操作

获取到ObjectWriter之后,就可以进行write()操作了,JSON.toJSONString()入口:

objectWriter.write((JSONWriter)writer, object, (Object)null, (Type)null, 0L);

由于自定义类的ObjectWriter是运行时拿到的,无法通过调试获取到,但是可以通过内置的ObjectWriter来判断大概的write()流程:

比如LocalDateWriterwrite()如下:

public void write(JSONWriter jsonWriter, Object object, Object fieldName, Type fieldType, long features) {try {int year = (Integer)this.getYear.invoke(object);int monthOfYear = (Integer)this.getMonthOfYear.invoke(object);int dayOfMonth = (Integer)this.getDayOfMonth.invoke(object);Object chronology = this.getChronology.invoke(object);if (chronology != this.utc && chronology != null) {jsonWriter.startObject();// 写入keyjsonWriter.writeName("year");// 写入valuejsonWriter.writeInt32(year);jsonWriter.writeName("month");jsonWriter.writeInt32(monthOfYear);jsonWriter.writeName("day");jsonWriter.writeInt32(dayOfMonth);jsonWriter.writeName("chronology");jsonWriter.writeAny(chronology);jsonWriter.endObject();} else {LocalDate localDate = LocalDate.of(year, monthOfYear, dayOfMonth);DateTimeFormatter formatter = this.getDateFormatter();if (formatter == null) {formatter = jsonWriter.getContext().getDateFormatter();}if (formatter == null) {jsonWriter.writeLocalDate(localDate);} else {String str = formatter.format(localDate);jsonWriter.writeString(str);}}} catch (InvocationTargetException | IllegalAccessException var14) {throw new JSONException("write LocalDateWriter error", var14);}}

根据getter获取字段值并调用对应的Writer去写JSON

3.2 反序列化

3.2.1 概览

反序列化也可以参考官方的一张图:

大概流程与序列化类似:

  • 获取ObjectReader
  • 如果ObjectReaderProvider有缓存,从缓存提取
  • 如果ObjectReaderProvider没有缓存,创建ObjectReader并且缓存到ObjectReaderProvider
  • 通过JSONReader得到Object
  • 返回结果

3.2.2 入口

Entity entity = Entity.builder().field1("a").field2(2).build();String str = JSON.toJSONString(entity);System.out.println(JSON.parseObject(str,Entity.class));

其中parseObject()如下:

static <T> T parseObject(String text, Class<T> clazz) {if (text != null && !text.isEmpty()) {// 获取JSONReaderJSONReader reader = JSONReader.of(text);Object var7;try {JSONReader.Context context = reader.context;// 判断是否基于字段反序列化boolean fieldBased = (context.features & Feature.FieldBased.mask) != 0L;// 通过ObjectReaderProvider获取ObjectReader// 这个context看起来和ObjectReaderProvider无关,实际上内部实现Context包含了ObjectReaderProviderObjectReader<T> objectReader = context.provider.getObjectReader(clazz, fieldBased);// 反序列化核心方法T object = objectReader.readObject(reader, (Type)null, (Object)null, 0L);if (reader.resolveTasks != null) {reader.handleResolveTasks(object);}if (reader.ch != 26 && (reader.context.features & Feature.IgnoreCheckClose.mask) == 0L) {throw new JSONException(reader.info("input not end"));}var7 = object;} catch (Throwable var9) {if (reader != null) {try {reader.close();} catch (Throwable var8) {var9.addSuppressed(var8);}}throw var9;}if (reader != null) {reader.close();}return var7;} else {return null;}}

3.2.3 获取JSONReader

JSON.parseObject()入口:

JSONReader reader = JSONReader.of(text);

其中JSONReader.of()实现如下:

public static JSONReader of(String str) {if (str == null) {throw new NullPointerException();} else {// 创建Context// Context内部包含了ObjectReaderProviderContext context = JSONFactory.createReadContext();int length;// 测试环境JDK8,此处if不成立if (JDKUtils.JVM_VERSION > 8 && JDKUtils.UNSAFE_SUPPORT) {try {length = JDKUtils.STRING_CODER != null " />JDKUtils.STRING_CODER.applyAsInt(str) : UnsafeUtils.getStringCoder(str);if (length == 0) {byte[] bytes = JDKUtils.STRING_VALUE != null ? (byte[])JDKUtils.STRING_VALUE.apply(str) : UnsafeUtils.getStringValue(str);return new JSONReaderASCII(context, str, bytes, 0, bytes.length);}} catch (Exception var4) {throw new JSONException("unsafe get String.coder error");}}length = str.length();char[] chars;// 测试环境JDK8if (JDKUtils.JVM_VERSION == 8) {// 获取char arraychars = JDKUtils.getCharArray(str);} else {chars = str.toCharArray();}// 由于JDK8的String还是使用char[]实现的,所以返回UTF16的JSONReaderreturn new JSONReaderUTF16(context, str, chars, 0, length);}}

3.2.4 获取ObjectReader

JSON.parseObject()入口:

ObjectReader<T> objectReader = context.provider.getObjectReader(clazz, fieldBased);

getObjectReader()如下:

public ObjectReader getObjectReader(Type objectType, boolean fieldBased) {if (objectType == null) {objectType = Object.class;}// 有缓存直接从缓存提取ObjectReader objectReader = fieldBased ? (ObjectReader)this.cacheFieldBased.get(objectType) : (ObjectReader)this.cache.get(objectType);// 第一次获取ObjectReader为nullif (objectReader != null) {return objectReader;} else {Iterator var4 = this.modules.iterator();ObjectReader previous;while(var4.hasNext()) {ObjectReaderModule module = (ObjectReaderModule)var4.next();// 获取到的ObjectReader为nullobjectReader = module.getObjectReader(this, (Type)objectType);if (objectReader != null) {previous = fieldBased ? (ObjectReader)this.cacheFieldBased.putIfAbsent(objectType, objectReader) : (ObjectReader)this.cache.putIfAbsent(objectType, objectReader);if (previous != null) {objectReader = previous;}return objectReader;}}Type rawType;// 条件不符合if (objectType instanceof TypeVariable) {Type[] bounds = ((TypeVariable)objectType).getBounds();if (bounds.length > 0) {rawType = bounds[0];if (rawType instanceof Class) {previous = this.getObjectReader(rawType, fieldBased);if (previous != null) {ObjectReader previous = this.getPreviousObjectReader(fieldBased, (Type)objectType, previous);if (previous != null) {previous = previous;}return previous;}}}}// 条件不符合if (objectType instanceof ParameterizedType) {ParameterizedType parameterizedType = (ParameterizedType)objectType;rawType = parameterizedType.getRawType();Type[] typeArguments = parameterizedType.getActualTypeArguments();if (rawType instanceof Class) {Class rawClass = (Class)rawType;boolean generic = false;for(Class clazz = rawClass; clazz != Object.class; clazz = clazz.getSuperclass()) {if (clazz.getTypeParameters().length > 0) {generic = true;break;}}if (typeArguments.length == 0 || !generic) {ObjectReader rawClassReader = this.getObjectReader(rawClass, fieldBased);if (rawClassReader != null) {ObjectReader previous = this.getPreviousObjectReader(fieldBased, (Type)objectType, rawClassReader);if (previous != null) {rawClassReader = previous;}return rawClassReader;}}}}Class<?> objectClass = TypeUtils.getMapping((Type)objectType);String className = objectClass.getName();if (objectReader == null && !fieldBased) {switch (className) {// 针对Guava的MultiMap,这里的条件不符合case "com.google.common.collect.ArrayListMultimap":objectReader = ObjectReaderImplMap.of((Type)null, objectClass, 0L);}}// ObjectReader为nullif (objectReader == null) {// 获取ObjectReaderCreatorObjectReaderCreator creator = this.getCreator();// 创建ObjectReaderobjectReader = creator.createObjectReader(objectClass, (Type)objectType, fieldBased, this);}previous = this.getPreviousObjectReader(fieldBased, (Type)objectType, objectReader);if (previous != null) {objectReader = previous;}return objectReader;}}

在创建ObjectReader的同时,会在其中创建FieldReader

// ObjectReaderCreator.java 453FieldReader[] fieldReaderArray = this.createFieldReaders(objectClass, objectType, beanInfo, fieldBased, provider);

3.2.5 read()操作

有了ObjectReader之后就可以进行具体的read()操作了,JSON.parseObject()入口:

T object = objectReader.readObject(reader, (Type)null, (Object)null, 0L);

此处的readObject()如下:

// ObjectReaderNoneDefaultConstructor.java 171行public T readObject(JSONReader jsonReader, Type fieldType, Object fieldName, long features) {// 判断是否带有JSONReader.Feature.ErrorOnNoneSerializableif (!this.serializable) {jsonReader.errorOnNoneSerializable(this.objectClass);}// 是否JSONB,不符合if (jsonReader.isJSONB()) {return this.readJSONBObject(jsonReader, fieldType, fieldName, 0L);} else if (jsonReader.isArray() && jsonReader.isSupportBeanArray(features | this.features)) {// 是数组而且支持JSONReader.Feature.SupportArrayToBean,不符合jsonReader.next();LinkedHashMap<Long, Object> valueMap = null;for(int i = 0; i < this.fieldReaders.length; ++i) {Object fieldValue = this.fieldReaders[i].readFieldValue(jsonReader);if (valueMap == null) {valueMap = new LinkedHashMap();}long hash = this.fieldReaders[i].fieldNameHash;valueMap.put(hash, fieldValue);}if (!jsonReader.nextIfMatch(']')) {throw new JSONException(jsonReader.info("array not end, " + jsonReader.current()));} else {jsonReader.nextIfMatch(',');return this.createInstanceNoneDefaultConstructor((Map)(valueMap == null ? Collections.emptyMap() : valueMap));}} else {// 读取字符boolean objectStart = jsonReader.nextIfObjectStart();// 条件为false,进入elseif (!objectStart && !jsonReader.isTypeRedirect() && jsonReader.nextIfEmptyString()) {return null;} else {// 获取Context,读取其中的FeaturesJSONReader.Context context = jsonReader.getContext();long featuresAll = this.features | features | context.getFeatures();// 此处存储对象的值// key是字段的long哈希值,哈希采取的是fnv1a 64算法生成的// value是字段的具体值LinkedHashMap<Long, Object> valueMap = null;// 读取for(int i = 0; !jsonReader.nextIfMatch('}'); ++i) {// 读取字段名对应的hashCodelong hashCode = jsonReader.readFieldNameHashCode();if (hashCode != 0L) {if (hashCode == this.typeKeyHashCode && i == 0) {long typeHash = jsonReader.readTypeHashCode();// 此处if条件不符合if (typeHash != this.typeNameHash) {boolean supportAutoType = (featuresAll & Feature.SupportAutoType.mask) != 0L;ObjectReader autoTypeObjectReader;String typeName;if (supportAutoType) {autoTypeObjectReader = context.getObjectReaderAutoType(typeHash);if (autoTypeObjectReader == null) {typeName = jsonReader.getString();autoTypeObjectReader = context.getObjectReaderAutoType(typeName, this.objectClass, this.features);}} else {typeName = jsonReader.getString();autoTypeObjectReader = context.getObjectReaderAutoType(typeName, this.objectClass);}if (autoTypeObjectReader == null) {typeName = jsonReader.getString();autoTypeObjectReader = context.getObjectReaderAutoType(typeName, this.objectClass, this.features);}if (autoTypeObjectReader != null) {Object object = autoTypeObjectReader.readObject(jsonReader, fieldType, fieldName, 0L);jsonReader.nextIfMatch(',');return object;}}} else {// 获取字段名哈希对应的FieldReaderFieldReader fieldReader = this.getFieldReader(hashCode); // 条件不符合if (fieldReader == null && (featuresAll & Feature.SupportSmartMatch.mask) != 0L) {long hashCodeLCase = jsonReader.getNameHashCodeLCase();if (hashCodeLCase != hashCode) {fieldReader = this.getFieldReaderLCase(hashCodeLCase);}}// fieldReader不为nullif (fieldReader == null) {this.processExtra(jsonReader, (Object)null);} else {// 读取字段值Object fieldValue = fieldReader.readFieldValue(jsonReader);if (valueMap == null) {valueMap = new LinkedHashMap();}long hash;if (fieldReader instanceof FieldReaderObjectParam) {hash = ((FieldReaderObjectParam)fieldReader).paramNameHash;} else {hash = fieldReader.fieldNameHash;}// 写入valueMap.put(hash, fieldValue);}}}}// 构造对象T object = this.createInstanceNoneDefaultConstructor((Map)(valueMap == null ? Collections.emptyMap() : valueMap));if (this.setterFieldReaders != null && valueMap != null) {for(int i = 0; i < this.setterFieldReaders.length; ++i) {FieldReader fieldReader = this.setterFieldReaders[i];// 读取字段值Object fieldValue = valueMap.get(fieldReader.fieldNameHash);if (fieldValue != null) {// 通过setter注入fieldReader.accept(object, fieldValue);}}}jsonReader.nextIfMatch(',');return object;}}}

4 结尾

其实文章中很多细节的地方由于篇幅的限制无法过于详细的解释,比如内置的各类型的Reader/Writer具体是如何获取值进行序列化/反序列操作的,想要深入探究这部分就只能自己去挖源码了。另外需要注意的是,文章的环境是在JDK8下的,由于Fastjson2在不同的JDK下会有不同的序列化实现,因此仅供参考。

最后,关于性能的比较,可以参考官方的比较基准。

5 参考

  • Fastjson2 Github
  • Fastjson2 Wiki