性能文章>Gson 核心流程源码与对应设计模式浅析>

Gson 核心流程源码与对应设计模式浅析原创

414929

1 Gson 简介

​ 前段时间在回顾java反射相关知识体系时,看到了Gson里面处理泛型类型数据序列化与反序列化相关的代码。于是便想深入地了解一下Gson内部是怎么实现Json字符串与Java对象之间的相互转换。

​ Github上Gson代码库的wiki上描述了Gson的目标有下面几个。

1、提供简单的toJson与fromJson方法实现Java对象与JSON之间的相互转换。

2、允许将预先存在的不可修改对象与 JSON之间的相互转换。

3、对Java泛型的扩展支持,即能实现泛型类型Java对象与JSON之间的相互转换。

4、允许对象的自定义表示,即能通过配置或注解实现转换的自定义,如Java与JSON命名风格自定义(Java中变量采用驼峰命名,而JSON中key采用下划线命名)、转换时支持版本定义、转换时忽略部分变量等。

5、支持任意复杂对象时,Java对象与JSON之间的相互转换,如Java中的多层继承层、泛型类型等。

可以看到Gson库要解决的核心问题是提供便捷的接口实现Java对象与JSON之间的相互转换,即wiki目标中的第一条,而剩下的目标都是目标一的深化与细化。

​ 以JSON对象转换为Java对象为例,其整体可分为如下三步。

1、通过反射创建目标类型的Java对象

2、把JSON中对应的值赋给Java对象的属性

3、返回Java对象

其中,最复杂的一步是第二步,因在解析JSON字符串并赋值给Java对象属性时,可能会存在递归的过程,即JSON中某个键值对对应的value本身不是JSON的基本类型(String、Number、Boolean、null),而是一个复杂类型,即是Object或Array。如下面的人员信息的JSON,其中的key address还是一个JSON的Object。

{"name":"叶易","profession":"架构师", "address":{"province":"江西","city":"南昌", "area":"东湖区北京东路555号C6"}}
复制代码

2 Gson 核心类TypeAdapter

2.1 待处理数据类型与TypeAdapter的关系

​ Gson内部在处理JSON数据时将数据类型分为基本类型与复杂类型,基本类型指的是JSON中String、Number、Boolean、null类型的值,复杂类型指的是JSON中Object或Array类型的值。Gson中不管是处理基本类型与复杂类型都会使用TypeAdapter具体实现去处理。TypeAdapter抽象类的定义如下(下面所有源码分析,Gson版本都为2.8.0)。

public abstract class TypeAdapter<T> {
  //负责Java对象转换成JSON,通过JsonWriter,将value对象内对应属性写入流中。
  public abstract void write(JsonWriter out, T value) throws IOException;
  //负责JSON转换成Java对象,通过JsonReader,将流中对应的JSON转换为Java对象T
  public abstract T read(JsonReader in) throws IOException;
}
复制代码

​ TypeAdapter内部定义了write与read方法,write方法负责将Java对象转换成JSON,而read方法负责将JSON转换成Java对象。正如TypeAdapter的命名,TypeAdapter这个类采用了适配器模式,其职责是适配Java对象与JSON之间的转换。Gson在处理序列化与反序列化时,首要的任务是选将要处理的对象与对象属性对应的TypeAdapter给确定好,然后再调用TypeAdapter的write或是read方法去执行序列化与反序列化。

​ Gson会为每一种类型定义具体的TypeAdapter,根据处理类型的不同,TypeAdapter可以归纳处理基本类型与处理复杂类型这两类。处理基本类型的TypeAdapter指的是用于处理JSON中String、Number、Boolean、null类型的值;处理复杂类型的TypeAdapter指的是用于处理JSON中Object或Array类型的值。Gson中处理基本类型的TypeAdapter都定义在TypeAdapters类中为其内部匿名类;而处理复杂类型的TypeAdapter则定义在ReflectiveTypeAdapterFactory中为其内部类Adapter。

​ 处理基本类型的TypeAdapter都是定义在TypeAdapters内中与TypeAdapter成对出现是创建他的TypeAdapterFactory。这里拿处理JSON基本类型Nubmer与Java类型Integer相互转换的TypeAdapter来看一下,该TypeAdapter是TypeAdapters类中的成员变量INTEGER。

public static final TypeAdapter<Number> INTEGER = new TypeAdapter<Number>() {
  @Override
  public Number read(JsonReader in) throws IOException {
    //JSON对应key对应值为null的判断
    if (in.peek() == JsonToken.NULL) {
      in.nextNull();
      return null;
    }
    try {
      //从流中直接读取integer类型的值,在JSON中对应是Number类型
      return in.nextInt();
    } catch (NumberFormatException e) {
      throw new JsonSyntaxException(e);
    }
  }
  @Override
  public void write(JsonWriter out, Number value) throws IOException {
    out.value(value);
  }
};
复制代码

​ 可以看到INTEGER这个TypeAdapter的源码,处理JSON与Java类型互相转换的逻辑很简单。TypeAdapters中还有很多类型为TypeAdapter的成变量用于处理JSON基本类型与Java类型的转换。由于JSON中一些基本类型能映射成不同的Java类型,如JSON中的Nubmer类型可以映射成Java中的Double、可以映射成Java中的Float、也可以映射成Java中的BigDecimal,所以TypeAdapters中有DOUBLE、FLOAT、BIG_DECIMAL等等许多处理JSON基本类型与Java类型的转换的TypeAdapter。

​ 处理复杂类型的Adapter源码相对复杂点,其是ReflectiveTypeAdapterFactory的内部类。下面Adapter源码中的read与write的具体实现先省略,后面再分析。这里我们关注的重点放在Adapter这个TypeAdapter是如何构建的与Adapter有什么成员变量。在创建Adapter实例时,传递进来两个重要的参数为Adapter的成员变量constructor与boundFields赋值。类型为ObjectConstructor的constructor用于处理反序列化时构建对应的实例;而类型为BoundField的boundFields,用于处理对应类型属性的序列化与反序列化,BoundField这个类在处理属性的序列化与反序列化时,最终还是会调用TypeAdapter去处理(BoundField的源码也放到后面分析)。

public static final class Adapter<T> extends TypeAdapter<T> {
  private final ObjectConstructor<T> constructor;
  //用于处理对应类型属性序列化与反序列化的BoundField,BoundField处理属性的序列化与反序列化时,最终还是会调用TypeAdapter去处理
  private final Map<String, BoundField> boundFields;
  Adapter(ObjectConstructor<T> constructor, Map<String, BoundField> boundFields) {
    this.constructor = constructor;
    this.boundFields = boundFields;
  }
  @Override 
  public T read(JsonReader in) throws IOException {
   //省略源码实现
  }
  @Override 
  public void write(JsonWriter out, T value) throws IOException {
    //省略源码实现
  }
}
复制代码
2.2 为什么说TypeAdapter是Gson中的核心

​ Gson在处理序列化与反序列化时,首要的任务是先将要处理对象与其属性对应的TypeAdapter给确定好,没有对应的TypeAdapter后面就没办法调用TypeAdapter的write或是read方法去执行序列化与反序列化操作。从前面的TypeAdapters成员变量INTEGER的源码分析可以看到,Gson在处理基本类型的序列化与反序列化操作的逻辑都相对简单;而真正复杂的逻辑还是在处理复杂类型上,在处理复杂类型时,首先要获取其对应的Adapter,同时还要遍历其所有属性构建BoundField用于处理其属性的序列化与反序列化。

Gson中TypeAdapter获取.png

​ 上面是通过目标类型如何利用Gson#getAdapter去获取对应的 TypeAdapter与构建BoundField的整体流程,这个图对于理解Gson的核心流程来说是很重要的。在利用Gson#getAdapter去获取对应的 TypeAdapter时,源码实现上如果不适当的处理会出现很严重的问题,不知道你是否发现了问题,如果通过上面这个流程图就是意识到潜在的严重问题,在下只能说佩服佩服佩服👍👍👍,后面会详细分析这部分涉及的源码。

2.3 TypeAdapter创建与调用过程

​ Gson中定义了一个名为TypeAdapterFactory类,该类采用了工厂方法设计模式来创建TypeAdapter。

public interface TypeAdapterFactory {
  //Returns a type adapter for {@code type}, or null if this factory doesn't support {@code type}.
  <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type);
}
复制代码

​ 如上TypeAdapterFactory中定义了唯一的create方法,该方法有两个参数,类型为Gson的参数gson为创建TypeAdapter的上下文,类型为TypeToken的参数type为待创建TypeAdapter类型的描述,通过TypeToken Gson扩展支撑了泛型类型对象的处理。create方法会根据TypeToken的擦除类型生成相应的TypeAdapter实例,如果当前Factory不支持TypeToken的擦除类型,则直接返回null。

​ 那TypeAdapterFactory这个Factory有哪些具体实现呢?前面说过Gson的TypeAdapter在处理Java对象与JSON的转换时,将类型划分为基本类型与复杂类型,同样我们可以将TypeAdapterFactory划分为处理基本类型的TypeAdapterFactory与处理复杂类型的TypeAdapterFactory,前者的定义基本集中在TypeAdapters类中,而后者以ReflectiveTypeAdapterFactory类为代表,当然还有MapTypeAdapterFactory、CollectionTypeAdapterFactory等。

​ 这里我们来看一下前面分析过的TypeAdapters中成员变量INTEGER对应TypeAdapterFactory源码。

//利用通的方法构建对应的TypeAdapterFactory实例
public static final TypeAdapterFactory INTEGER_FACTORY = newFactory(int.class, Integer.class, INTEGER);
//通用的newFactory方法,根据类型返回对应的TypeAdapterFactory
public static <TT> TypeAdapterFactory newFactory(
      final Class<TT> unboxed, final Class<TT> boxed, final TypeAdapter<? super TT> typeAdapter) {
  return new TypeAdapterFactory() {
    @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
    @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
      //获取typeToken对应的擦除类型,即原始类型
      Class<? super T> rawType = typeToken.getRawType();
      //原始类型与目标类型一致或目标类型的原始类型一致则返回对应的TypeAdapter,当前例子返回的是INTEGER对应的TypeAdapter
      return (rawType == unboxed || rawType == boxed) ? (TypeAdapter<T>) typeAdapter : null;
    }
    @Override public String toString() {
      return "Factory[type=" + boxed.getName()
        + "+" + unboxed.getName() + ",adapter=" + typeAdapter + "]";
    }
  };
}
复制代码

​ 在TypeAdapters类中有一系列的匿名内部类用于处理JSON中的基本类型String、Number、Boolean、null与Java类型的转换。这些内部匿名类以TypeAdapter和TypeAdapterFactory的形式成对出现。

​ 上面说到对于复杂类型其对应的TypeAdapter为Adapter,其对应的TypeAdapterFactory为ReflectiveTypeAdapterFactory。Adapter为ReflectiveTypeAdapterFactory的内部类,其源码如下。

public static final class Adapter<T> extends TypeAdapter<T> {
  //T类型对应的构造器
  private final ObjectConstructor<T> constructor;
  //用于处理对应类型T属性序列化与反序列化的BoundField,BoundField处理属性的序列化与反序列化时,最终还是会调用TypeAdapter去处理
  private final Map<String, BoundField> boundFields;
  Adapter(ObjectConstructor<T> constructor, Map<String, BoundField> boundFields) {
    this.constructor = constructor;
    this.boundFields = boundFields;
  }
  @Override 
  public T read(JsonReader in) throws IOException {
    if (in.peek() == JsonToken.NULL) {
      in.nextNull();
      return null;
    }
    //1、通过反射创建T类型对应实例instance
    T instance = constructor.construct();
    try {
      //开始处理JSON对应的输入流
      in.beginObject();
      //2、逐个处理JSON的键值对
      while (in.hasNext()) {
        //获取JSON中下一个键值对,对应key的名称
        String name = in.nextName();
        //根据key的名称,获取其对应属性限制
        BoundField field = boundFields.get(name);
        //JSON中对应的key在Java对象中无对应的属性或当前key不用反序列化
        if (field == null || !field.deserialized) {
          in.skipValue();
        } else {
          //3、为instance对应属性设置值,该方法内部可能会再次递归调用Adapter#read方法
          field.read(in, instance);
        }
      }
    } catch (IllegalStateException e) {
      throw new JsonSyntaxException(e);
    } catch (IllegalAccessException e) {
      throw new AssertionError(e);
    }
    in.endObject();
    return instance;
  }
  @Override 
  public void write(JsonWriter out, T value) throws IOException {
    if (value == null) {
      out.nullValue();
      return;
    }
    out.beginObject();
    try {
      for (BoundField boundField : boundFields.values()) {
        if (boundField.writeField(value)) {
          out.name(boundField.name);
          boundField.write(out, value);
        }
      }
    } catch (IllegalAccessException e) {
      throw new AssertionError(e);
    }
    out.endObject();
  }
}
复制代码

​ 以Adapter的read方法为例,在将JSON转换为Java对象时,其首先通过反射创建T类型对应实例instance,然后逐个处理JSON的键值对,最后通过判断决定是否要处理该键值对,如果要处理则为instance对应属性设置值(该步可能会递归重复上面的流程)。Adapter的read方法引用的BoundField类,其定义如下。

static abstract class BoundField {
  //属性对应的名称
  final String name;
  //属性是否要序列化
  final boolean serialized;
  //属性是否要反序列化
  final boolean deserialized;
  protected BoundField(String name, boolean serialized, boolean deserialized) {
    this.name = name;
    this.serialized = serialized;
    this.deserialized = deserialized;
  }
  //负责java对象转换成JSON
  abstract boolean writeField(Object value) throws IOException, IllegalAccessException;
 	//负责java对象转换成JSON
  abstract void write(JsonWriter writer, Object value) throws IOException, IllegalAccessException;
  //负责JSON转换成Java对象
  abstract void read(JsonReader reader, Object value) throws IOException, IllegalAccessException;
}
复制代码

​ BoundField本身为抽象类,Adapter引用的BoundField是在ReflectiveTypeAdapterFactory在创建Adapter时传递过来的。直接看一下ReflectiveTypeAdapterFactory中用于创建Adapter的create方法。

@Override 
public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) {
  Class<? super T> raw = type.getRawType();
  //ReflectiveTypeAdapterFactory不处里基本类型,即其不支持基本类型所以直接返回null
  if (!Object.class.isAssignableFrom(raw)) {
    return null; // it's a primitive!
  }
  ObjectConstructor<T> constructor = constructorConstructor.get(type);
  //构造Adapter实例前先调用getBoundFields方法创建对应类型所有属性的BoundField
  return new Adapter<T>(constructor, getBoundFields(gson, type, raw));
}
//根据类型创建,该类型所有属性对应的BoundField,并通过属性名与BoundField映射关系形式返回
private Map<String, BoundField> getBoundFields(Gson context, TypeToken<?> type, Class<?> raw) {
  Map<String, BoundField> result = new LinkedHashMap<String, BoundField>();
  if (raw.isInterface()) {
    return result;
  }
  Type declaredType = type.getType();
  //根据继承关系依次向上逐层处理属性名与BoundField的映射
  while (raw != Object.class) {
    //获取当前raw类型本身声明的所有字段(不会返回父类或超类中声明的字段)
    Field[] fields = raw.getDeclaredFields();
    for (Field field : fields) {
      boolean serialize = excludeField(field, true);
      boolean deserialize = excludeField(field, false);
      //当前属性不参与序列化与反序列化,直接跳过
      if (!serialize && !deserialize) {
        continue;
      }
      field.setAccessible(true);
      //获取属性的实际类型
      Type fieldType = $Gson$Types.resolve(type.getType(), raw, field.getGenericType());
      //根据已配置的规则返回字段能生成的所有属性名称list
      List<String> fieldNames = getFieldNames(field);
      BoundField previous = null;
      //逐处理对应的属性名
      for (int i = 0; i < fieldNames.size(); ++i) {
        String name = fieldNames.get(i);
        if (i != 0) serialize = false; // only serialize the default name
        //创建属性对应的BoundField
        BoundField boundField = createBoundField(context, field, name, TypeToken.get(fieldType), 
                  	serialize, deserialize);
        //如果name之前已绑定BoundField,则会返回之间绑定的BoundField
        BoundField replaced = result.put(name, boundField);
        if (previous == null) previous = replaced;
      }
      //previous不为空,即上面replaced不为空,表明已存在的BoundField被替换了,相当于类本身有对应的属性,父又声明了对应的属性
      if (previous != null) {
        throw new IllegalArgumentException(declaredType
                           + " declares multiple JSON fields named " + previous.name);
      }
    }
    //获取父类对应的TypeToken
    type = TypeToken.get($Gson$Types.resolve(type.getType(), raw, raw.getGenericSuperclass()));
    //获取父类对应的的擦除类型
    raw = type.getRawType();
  }
  return result;
}
复制代码

​ 上面的getBoundFields方法主要功能是根据继承关系依次向上逐层处理封装BoundField,并将字段名作为key,BoundField作为value放入Map最后返回。从getBoundFields源码分析中可以看到Gson是不支持子类中声明父类同名属性对象的序列化与反序列化操作的(通过注解忽略子类或父其中某一个属性,或两者时当然是可以的)。

​ getBoundFields方法在封装BoundField时,内部调用实际调用了createBoundField方法,其源码如下。

private ReflectiveTypeAdapterFactory.BoundField createBoundField(
      final Gson context, final Field field, final String name,
      final TypeToken<?> fieldType, boolean serialize, boolean deserialize) {
  final boolean isPrimitive = Primitives.isPrimitive(fieldType.getRawType());
  //获取字段上对应的JsonAdapter注解
  JsonAdapter annotation = field.getAnnotation(JsonAdapter.class);
  TypeAdapter<?> mapped = null;
  //字段上存在对应的JsonAdapter注解,通过JsonAdapterAnnotationTypeAdapterFactory获取对应的TypeAdapter实例
  if (annotation != null) {
    mapped = jsonAdapterFactory.getTypeAdapter(constructorConstructor, context, fieldType, annotation);
  }
  final boolean jsonAdapterPresent = mapped != null;
  //尝试从Gson中获取对应的typeAdapter
  if (mapped == null) mapped = context.getAdapter(fieldType);
  final TypeAdapter<?> typeAdapter = mapped;
  return new ReflectiveTypeAdapterFactory.BoundField(name, serialize, deserialize) {
    @Override 
    void write(JsonWriter writer, Object value) throws IOException, IllegalAccessException {
       Object fieldValue = field.get(value);
       TypeAdapter t = jsonAdapterPresent ? typeAdapter
         : new TypeAdapterRuntimeTypeWrapper(context, typeAdapter, fieldType.getType());
       t.write(writer, fieldValue);
     }
    @Override 
    void read(JsonReader reader, Object value) throws IOException, IllegalAccessException {
      //通过已获取到的typeAdapter,读取输入流中对应的属性值
      Object fieldValue = typeAdapter.read(reader);
      if (fieldValue != null || !isPrimitive) {
        field.set(value, fieldValue);
      }
    }
    @Override
    public boolean writeField(Object value) throws IOException, IllegalAccessException {
      if (!serialized) return false;
      Object fieldValue = field.get(value);
      return fieldValue != value; // avoid recursion for example for Throwable.cause
    }
    //省略部分源码
  };
}
复制代码

​ 通过上源码的可以看到BoundField定义的write与read方法内部实际上分别调用了TypeAdapter的write与read方法。而TypeAdapter的获取最终又由委派给了传入的Gson实例,context.getAdapter(fieldType)对应的源码如下。

public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
  //从全局ConcurrentHashMap类型的typeTokenCache变量中获取对应TypeToken缓存的TypeAdapter
  TypeAdapter<?> cached = typeTokenCache.get(type == null ? NULL_KEY_SURROGATE : type);
  //缓存的TypeAdapter缓存直接返回
  if (cached != null) {
    return (TypeAdapter<T>) cached;
  }
  //从ThreadLocal类型的calls变量中获取当前线程绑定的TypeToken与FutureTypeAdapter的映射关系
  Map<TypeToken<?>, FutureTypeAdapter<?>> threadCalls = calls.get();
  boolean requiresThreadLocalCleanup = false;
  //线程上之前未通过ThreadLocal绑定TypeToken与FutureTypeAdapter的映射关系,创建映射关系并绑定
  if (threadCalls == null) {
    threadCalls = new HashMap<TypeToken<?>, FutureTypeAdapter<?>>();
    calls.set(threadCalls);
    requiresThreadLocalCleanup = true;
  }
  // the key and value type parameters always agree
  FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type);
  if (ongoingCall != null) {
    return ongoingCall;
  }
  try {
    FutureTypeAdapter<T> call = new FutureTypeAdapter<T>();
    threadCalls.put(type, call);
    //遍历创建Gson时,所有已配置TypeAdapterFactory,找到候选的TypeAdapter并返回
    for (TypeAdapterFactory factory : factories) {
      TypeAdapter<T> candidate = factory.create(this, type);
      //factory.create返回非null,代表该TypeAdapterFactory支持对应的TypeToken,直接返回
      if (candidate != null) {
        call.setDelegate(candidate);
        typeTokenCache.put(type, candidate);
        return candidate;
      }
    }
    throw new IllegalArgumentException("GSON cannot handle " + type);
  } finally {
    threadCalls.remove(type);
    if (requiresThreadLocalCleanup) {
      calls.remove();
    }
  }
}
复制代码

​ Gson#getAdapter方法主要功能是通过TypeToken,遍历所有已配置TypeAdapterFactory,然后找到对应候选的TypeAdapter,当找到当一个满足条件的TypeAdapter时,整个方法将返回TypeToken对应的TypeAdapter。上面的FutureTypeAdapter暂时有点难理解这里先放一下,后面再仔细分析一下他的作用。

​ 假设现在Gson#getAdapter返回是我们前面分析的TypeAdapters中的成员变量TypeAdapter INTEGER,即Integer类型对应的TypeAdapter。再来看一下createBoundField方法内部会怎么执行。

private ReflectiveTypeAdapterFactory.BoundField createBoundField(
      final Gson context, final Field field, final String name,
      final TypeToken<?> fieldType, boolean serialize, boolean deserialize) {
  //省略部分代码,假设Gson#getAdapter返回是Integer类型的TypeAdapter
  //即TypeAdapters中的成员变量TypeAdapter<Number> INTEGER
  if (mapped == null) mapped = context.getAdapter(fieldType);
  final TypeAdapter<?> typeAdapter = mapped;
  return new ReflectiveTypeAdapterFactory.BoundField(name, serialize, deserialize) {
    //省略部分源码
    @Override 
    void read(JsonReader reader, Object value) throws IOException, IllegalAccessException {
      //调用Integer类型的TypeAdapter的read方法从流中读取数据
      Object fieldValue = typeAdapter.read(reader);
      if (fieldValue != null || !isPrimitive) {
        field.set(value, fieldValue);
      }
    }
    //省略部分源码
  };
}
//Integer类型的TypeAdapter的read方法
public Number read(JsonReader in) throws IOException {
  //JSON对应key对应值为null的判断
  if (in.peek() == JsonToken.NULL) {
    in.nextNull();
    return null;
  }
  try {
    //从流中直接读取integer类型的值,在JSON中对应是Number类型
    return in.nextInt();
  } catch (NumberFormatException e) {
    throw new JsonSyntaxException(e);
  }
}
复制代码

​ 可以看到当要处理的属性为基本类型,比如上面假设的属性为Integer时,对应的TypeAdapter为TypeAdapters中的成员变量TypeAdapter INTEGER,其处理JSON值转换的逻辑就是直接转换对应值。

3 Gson解析JSON的流程

​ 前面在分析TypeAdapter创建与获取的流程时,或多或少顺带地分析了一下,Gson解析JSON的流程。这里我们在来重新以Gson解析JSON为例为分析一下Gson执行的整体流程。

3.1 Gson反序列化的整体流程
Gson gson = new Gson();
String jsonStr = "{\"name\":\"叶易\",\"profession\":\"架构师\", " 
			+ "\"address\":{\"province\":\"江西\",\"city\":\"南昌\", \"area\":\"东湖区北京东路555号C6\"}}";
Person person = gson.fromJson(jsonStr, Person.class); 
复制代码

​ 上面是调用Gson进行反序列化常见的代码。这里直接采用了Gson默认的配置生成Gson实例,然后传入JSON与目标类型调用fromJson方法,反序列化得到对应的Person对象。Gson#fromJson方法,内部执行流程大体可分析下面这些步骤。

1、通过Person对应的类型,获取对应的TypeAdapter。

2、通过获取的TypeAdapter(Adapter),调用read方法解析jsonStr中的内容,并赋值给Person实例。

3、返回设置完属性值的Person实例。

Gson#fromJson(String json, Class classOfT)方法最终会调用重载的Gson#fromJson(JsonReader reader, Type typeOfT)方法去解析JSON,源码如下。

public <T> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
    boolean isEmpty = true;
    boolean oldLenient = reader.isLenient();
    reader.setLenient(true);
    try {
      reader.peek();
      isEmpty = false;
      TypeToken<T> typeToken = (TypeToken<T>) TypeToken.get(typeOfT);
      //1、获取对应的TypeAdapter,上面的示例代码将返回ReflectiveTypeAdapterFactory内部类Adapter
      TypeAdapter<T> typeAdapter = getAdapter(typeToken);
      //2、调用对应TypeAdapter处理输入流读取数据,上面的示例代码是调用Adapter#read方法读取数据
      T object = typeAdapter.read(reader);
      //3、返回设置完属性值的实例
      return object;
    } catch (EOFException e) {
      //省略部分源码
    }
  }
复制代码

​ 可以看到fromJson方法的逻辑非常清晰明了,就是上面说的那三步,首先通过目标类型获取对应的TypeAdapter,然后调用TypeAdapter#read方法解析并设置对应数据,最后返回设置完属性的实例。现在再看一下fromJson方法内调用的getAdapter方法到底返回什么类型的TypeAdapter,虽然我们知道Person返回的TypeAdapter为Adapte。

public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
  //从全局ConcurrentHashMap类型的typeTokenCache变量中获取对应TypeToken缓存的TypeAdapter
  TypeAdapter<?> cached = typeTokenCache.get(type == null ? NULL_KEY_SURROGATE : type);
  //缓存的TypeAdapter缓存直接返回
  if (cached != null) {
    return (TypeAdapter<T>) cached;
  }
  //从ThreadLocal类型的calls变量中获取当前线程绑定的TypeToken与FutureTypeAdapter的映射关系
  Map<TypeToken<?>, FutureTypeAdapter<?>> threadCalls = calls.get();
  boolean requiresThreadLocalCleanup = false;
  //线程上之前未通过ThreadLocal绑定TypeToken与FutureTypeAdapter的映射关系,创建映射关系并绑定
  if (threadCalls == null) {
    threadCalls = new HashMap<TypeToken<?>, FutureTypeAdapter<?>>();
    calls.set(threadCalls);
    requiresThreadLocalCleanup = true;
  }
  // the key and value type parameters always agree
  FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type);
  if (ongoingCall != null) {
    return ongoingCall;
  }
  try {
    FutureTypeAdapter<T> call = new FutureTypeAdapter<T>();
    threadCalls.put(type, call);
    //遍历创建Gson时,所有已配置TypeAdapterFactory,找到候选的TypeAdapter并返回
    for (TypeAdapterFactory factory : factories) {
      TypeAdapter<T> candidate = factory.create(this, type);
      //factory.create返回非null,代表该TypeAdapterFactory支持对应的TypeToken,直接返回
      if (candidate != null) {
        call.setDelegate(candidate);
        typeTokenCache.put(type, candidate);
        return candidate;
      }
    }
    throw new IllegalArgumentException("GSON cannot handle " + type);
  } finally {
    threadCalls.remove(type);
    if (requiresThreadLocalCleanup) {
      calls.remove();
    }
  }
}
复制代码

​ 这段代码是不是很熟悉,没错我们在分析ReflectiveTypeAdapterFactory.BoundField的read方法到底是怎么执行时曾分析过这段代码,ReflectiveTypeAdapterFactory.BoundField的read方法实际会利用Gson#getAdapter方法返回对应的TypeAdapter,然后再将read的工作委派给返回的TypeAdapter实例的read方法去执行,也就是反序列化工作还是交给TypeAdapter#read方法。

3.2 Gson中配置的TypeAdapterFactory

​ 默认情况下Gson的构造函数中会配置很多类型的TypeAdapterFactory,以便调用Gson#getAdapter方法时,根据传入的TypeToken返回合适的TypeAdapter。

Gson(final Excluder excluder, final FieldNamingStrategy fieldNamingStrategy,
      final Map<Type, InstanceCreator<?>> instanceCreators, boolean serializeNulls,
      boolean complexMapKeySerialization, boolean generateNonExecutableGson,
      boolean htmlSafe,boolean prettyPrinting, boolean lenient,
      boolean serializeSpecialFloatingPointValues,
      LongSerializationPolicy longSerializationPolicy,
      List<TypeAdapterFactory> typeAdapterFactories) {
    //省略部分代码
    List<TypeAdapterFactory> factories = new ArrayList<TypeAdapterFactory>();
    // built-in type adapters that cannot be overridden
    factories.add(TypeAdapters.JSON_ELEMENT_FACTORY);
    factories.add(ObjectTypeAdapter.FACTORY);
    // the excluder must precede all adapters that handle user-defined types
    factories.add(excluder);
    // user's type adapters
    factories.addAll(typeAdapterFactories);
    // type adapters for basic platform types
    factories.add(TypeAdapters.STRING_FACTORY);
    factories.add(TypeAdapters.INTEGER_FACTORY);
    factories.add(TypeAdapters.BOOLEAN_FACTORY);
		//省略部分代码
    // type adapters for composite and user-defined types
    factories.add(new CollectionTypeAdapterFactory(constructorConstructor));
    factories.add(new MapTypeAdapterFactory(constructorConstructor, complexMapKeySerialization));
    this.jsonAdapterFactory = new JsonAdapterAnnotationTypeAdapterFactory(constructorConstructor);
    factories.add(jsonAdapterFactory);
    factories.add(TypeAdapters.ENUM_FACTORY);
    factories.add(new ReflectiveTypeAdapterFactory(
        constructorConstructor, fieldNamingStrategy, excluder, jsonAdapterFactory));
    this.factories = Collections.unmodifiableList(factories);
  }
复制代码

​ 上面是Gson构造函数的源码,Gson内部有一个List factories 的成员变量用于保存配置的TypeAdapterFactory,Gson的构造函数内部会向这个factories中加入处理基本类型对应的TypeAdapter的TypeAdapteFactory与处理复杂类型对应的TypeAdapte的TypeAdapteFactory。处理复杂类型的TypeAdapter的TypeAdapteFactory,也就是FactoryReflectiveTypeAdapterFactory被加上List的最后,这是因为在调用Gson#getAdapter方法时,会从前向后逐一遍历factories中的TypeAdapterFactory,如果当前的TypeAdapterFactory支持该类型,则会直接返回对应的TypeAdapter,而不会向后继续遍历。如果将FactoryReflectiveTypeAdapterFactory放在前面,那么遍历factories时,当传入的类型是String时,依旧会结束后面factories的遍历,导致真正的处理String类型的TypeAdapter没有被返回而是返回的处理复杂类型的Adapter。还是一点就是Gson的成员变是 factories构造好后就不能修改了。

4 Gson中如何解决获取嵌套类型对应的TypeAdapter循环调用问题

4.1 嵌套类型获取TypeAdapter可能出现的循环调用问题

​ 日常开发中定义嵌套的类型关系是很常见的场景, 比如存储数据节点之间的关系。

public class Node {
  private Node nextNode;
  private String nodeArea;
  private String nodeIp;
  ....
}
复制代码

注意:上面说的嵌套类型指的是类的属性本身就是该类,或者类的属性执有该类对应类型的成员变量,反正就是属性本身或属性的属性的属性去执有该类对应类型的成员变量

那Gson处理这种类型的对象会出现问题吗?答案一定的,肯定不会了啦,不然人家Google还怎么叫Google。那么处理这种嵌套的类型会出现什么问题呢?Gson又是如何解决这个问题的呢?

​ 下面这个通过目标类型调用Gson#getAdapter方法,获取对应的TypeAdapter的流程图还有印象不?之前说如果Gson源码对这个过程进行适当的处理,会产生严重的问题。

Gson中TypeAdapter获取.png ​ 假设现在传入的类型为上面定义的类Node,看看会有什么问题。当第一次传入类型Node调用Gson#getAdapter去获取TypeAdapter时,由于Node是复杂类型所以会调用 ReflectiveTypeAdapterFactory#create方法去创建Adapter,也就下面这段代码

@Override 
public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) {
  Class<? super T> raw = type.getRawType();
  if (!Object.class.isAssignableFrom(raw)) {
    return null; // it's a primitive!
  }
  ObjectConstructor<T> constructor = constructorConstructor.get(type);
  return new Adapter<T>(constructor, getBoundFields(gson, type, raw));
}
复制代码

而在构建最终返回的Adapter时,要先调用ReflectiveTypeAdapterFactory#getBoundFields方法为Node的所有属性创建对应的BoundField。ReflectiveTypeAdapterFactory#getBoundFields方法内部又会去调用ReflectiveTypeAdapterFactory# createBoundField方法去真正的创建BoundField,对应下面这段代码。

private ReflectiveTypeAdapterFactory.BoundField createBoundField(
      final Gson context, final Field field, final String name,
      final TypeToken<?> fieldType, boolean serialize, boolean deserialize) {
    final boolean isPrimitive = Primitives.isPrimitive(fieldType.getRawType());
    JsonAdapter annotation = field.getAnnotation(JsonAdapter.class);
    TypeAdapter<?> mapped = null;
    if (annotation != null) {
      mapped = jsonAdapterFactory.getTypeAdapter(
          constructorConstructor, context, fieldType, annotation);
    }
    final boolean jsonAdapterPresent = mapped != null;
  	//通过属性的类型再次调用Gson#getAdapter返回对应的TypeAdapter
  	//如果处理到Node的属性nextNode, 那么fieldType的类型将还是Node,似乎要出现死循环调用啦😂😂😂
    if (mapped == null) mapped = context.getAdapter(fieldType);
    final TypeAdapter<?> typeAdapter = mapped;
    return new ReflectiveTypeAdapterFactory.BoundField(name, serialize, deserialize) {
     //省略BoundField的read与write方法,实际就是调用typeAdapter的read与write方法
    };
  }
复制代码

​ 通过上面的调用分析可以知道,利用Gson#getAdapter的方法去获取TypeAdapter 会出现下面的调用链

Gson#getAdapter // 传入目标类型为Node

=>ReflectiveTypeAdapterFactory#create

=> ReflectiveTypeAdapterFactory#getBoundFields

=> ReflectiveTypeAdapterFactory#createBoundField

=> Gson#getAdapter // 传属性类型为Node

结合一下面之前流程图,可以看到当类型是Node这个这种嵌套类型时,这个调用链出现了死循环。

4.2 Gson 利用代理模型巧妙的处理循环调用问题

​ 通过上面的分析已清楚的知道,如果Gson#getAdapter方法内部不作适当的处理,当处理嵌套类型时是一定会发生循环调用的。那我们就回到Gson#getAdapter方法看一下,他到底是怎么处理循环调用的。还记得之前分析这个方法时与FutureTypeAdapter相关的东西没有分析吗?先看一下FutureTypeAdapter的源码吧。

static class FutureTypeAdapter<T> extends TypeAdapter<T> {
  private TypeAdapter<T> delegate;
  public void setDelegate(TypeAdapter<T> typeAdapter) {
    if (delegate != null) {
      throw new AssertionError();
    }
    delegate = typeAdapter;
  }
  @Override 
  public T read(JsonReader in) throws IOException {
    if (delegate == null) {
      throw new IllegalStateException();
    }
    return delegate.read(in);
  }
  @Override 
  public void write(JsonWriter out, T value) throws IOException {
    if (delegate == null) {
      throw new IllegalStateException();
    }
    delegate.write(out, value);
  }
}
复制代码

​ 这个FutureTypeAdapter,好像什么也没有做,就是利用代理模式,然后把所有序列化与反序列化的工作又代理给了他的成员变量delegate。但有一个重要的细节,就是我们可以先创建FutureTypeAdapter出来,然后再去设置他的成员变量delegate,所以这类被叫作了FutureTypeAdapter,意思是说你创建我出来的时候我实际还是不会为你工作的,等未来你设置了的代理实现(成员变量delegate),再让他去处理真正的序列化与反序列化工作吧。有了上面对FutureTypeAdapter的理解再去看一下Gson#getAdapter方法的源码是不是会柳暗花明又一村。

public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
  //从全局ConcurrentHashMap类型的typeTokenCache变量中获取对应TypeToken缓存的TypeAdapter
  TypeAdapter<?> cached = typeTokenCache.get(type == null ? NULL_KEY_SURROGATE : type);
  //缓存的TypeAdapter缓存直接返回
  if (cached != null) {
    return (TypeAdapter<T>) cached;
  }
  //从ThreadLocal类型的calls变量中获取当前线程绑定的TypeToken与FutureTypeAdapter的映射关系
  Map<TypeToken<?>, FutureTypeAdapter<?>> threadCalls = calls.get();
  boolean requiresThreadLocalCleanup = false;
  //线程上之前未通过ThreadLocal绑定TypeToken与FutureTypeAdapter的映射关系,创建映射关系并绑定
  if (threadCalls == null) {
    threadCalls = new HashMap<TypeToken<?>, FutureTypeAdapter<?>>();
    calls.set(threadCalls);
    requiresThreadLocalCleanup = true;
  }
  FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type);
  //再次调用同类型的TypeAdapter,反正只是想要一个TypeAdapterr,就先给返回一个还不能干活的FutureTypeAdapter
  //等真实的当前类型对应的真实TypeAdapter创建完后,再设置成FutureTypeAdapter的delegate让他去干活
  if (ongoingCall != null) {
    return ongoingCall;
  }
  try {
    //先创FutureTypeAdapter实例,当出理嵌套类型时,可以直接返回FutureTypeAdapter,
    //但这个FutureTypeAdapter实际还不能处理序列化与反序列化
    FutureTypeAdapter<T> call = new FutureTypeAdapter<T>();
    threadCalls.put(type, call);
    //遍历创建Gson时,所有已配置TypeAdapterFactory,找到候选的TypeAdapter并返回
    for (TypeAdapterFactory factory : factories) {
      TypeAdapter<T> candidate = factory.create(this, type);
      //factory.create返回非null,代表该TypeAdapterFactory支持对应的TypeToken,直接返回
      if (candidate != null) {
        //当真正的TypeAdapter创建完后,在将其设置到FutureTypeAdapter中
        //之前返回的不能干活的FutureTypeAdapter,现在可以让他的delegate干活了
        call.setDelegate(candidate);
        //创建成功后类型作为key,TypeAdapter作为value缓存在全局的ConcurrentHashMap中
        typeTokenCache.put(type, candidate);
        return candidate;
      }
    }
    throw new IllegalArgumentException("GSON cannot handle " + type);
  } finally {
    //对应TypeAdapter创建完后,在将FutureTypeAdapter从map中移走,同时对应值通过ThreadLocal与线程解绑
    threadCalls.remove(type);
    if (requiresThreadLocalCleanup) {
      calls.remove();
    }
  }
}
复制代码

​ 由于循环调用问题,只会出现在单调的调用中,所以Gson#getAdapter方法中解决循环调用问题直接利用ThreadLocal去将Type与FutureTypeAdapter的map与线程绑定。为了提高Gson#getAdapter获取TypeAdapter的效率,同类型对应的TypeAdapter一但被创建会被保存在全局的ConcurrentHashMap类型的typeTokenCache中。

总结

​ 本文分析了Gson在处理序列化与反序列化流程中核心类TypeAdapter相关的源码,介绍了其中采用的适配器设计模式、工厂方法设计模式、代理设计模式。Gson#getAdapter获取TypeAdapter的时采用的代理设计模式是非常的精妙,可以多次细品。

结尾

​ 原创不易,点赞、在看、转发是对我莫大的鼓励,关注公众号洞悉源码是对我最大的支持。同时相信我会分享更多干货,我同你一起成长,我同你一起进步

点赞收藏
叶易_公众号洞悉源码
请先登录,查看2条精彩评论吧
快去登录吧,你将获得
  • 浏览更多精彩评论
  • 和开发者讨论交流,共同进步

为你推荐

JDBC PreparedStatement 字段值为null导致TBase带宽飙升的案例分析

JDBC PreparedStatement 字段值为null导致TBase带宽飙升的案例分析

随机一门技术分享之Netty

随机一门技术分享之Netty

MappedByteBuffer VS FileChannel:从内核层面对比两者的性能差异

MappedByteBuffer VS FileChannel:从内核层面对比两者的性能差异

9
2