Gson源码解析

Posted microhex

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Gson源码解析相关的知识,希望对你有一定的参考价值。

基础了解

最近在解决一个Json解析时,把Gson原理过了一遍。Gson是Google开发的Json解析库,当然这种轮子市面上比较多,也不一一列举了。今天主要来聊聊Gson源码,是如何解析一个Json对象,然后按照葫芦画瓢,将一个Java对象如何序列化成 Json对象。

几个重要的概念

在分析Gson源码之前,首先需要在脑子中需要有这样几个概念,或者简单一点,我们先定义一个我们自己的抽象类:

1. 属性赋值/序列化

// 属性操作逻辑
abstract FieldOpertator {
    
    // 对象属性的读取
    abstract void read(); 
    
    // 对象属性的写入
    abstract void write();
}

对于FieldOpertator 来讲,可以理解为Java对象的属性赋值器/序列化,比如下面一个Java对象:

public class Person {
    
    public String name; 
    public int age;
    public String[] address;
}

那么Person对应的属性为name,ageaddress, 那么就分别存在对应的三个FieldOpertator来负责和序列化解析name,ageaddress.

2. Java类型适配器

这个说法可能会比较抽象,但是看到了上面的属性赋值/序列化之后,应该就会有一个大致的概念,PersonnameString型的,ageint型的,address是数组类型的,那么代码中会怎么识别,应该怎么知道它们分别是什么类型的呢?所以此时需要顶一个Java类型适配器,根据不同的java类型进行不同的适配,然后在不同的类型适配器里面做相关的工作即可。

public abstract class TypeAdapter<T> {
    
    
    abstract void read(T t);
    
    abstract void write(T t)
    
}

此时我们需要定义一个接口,通过Java属性的不同类型来获取到不同的 TypeAdapter,这里我们使用工厂方法获取接口逻辑。

public interface TypeAdapterFactory {

    <T> TypeAdapter<T> create(Type type);
    
}

这里的Type是 java类中的Class的顶级接口,可以理解为:

 System.out.println(String.class.getTypeName());
 System.out.println(List[].class.getTypeName());
 
//---out----
//java.lang.String
//java.util.List[]

3. JsonReader

给我们一段字符串,我们需要一个工具类来进行读取,比如我们需要读取的下一个字段为Int型数据,或者String型数据,这个工具类需要非常聪明的替我们完成要求。这里就不深入去说了,因为不是我们现在的主要目标。

源码分析

1. Gson初始化

首先我们在new Gson()的时候,首先需要知道我们干了些啥:

  public Gson() {
    this(Excluder.DEFAULT, 
        FieldNamingPolicy.IDENTITY,
        Collections.<Type, 
        InstanceCreator<?>>emptyMap(), 
        DEFAULT_SERIALIZE_NULLS,
        DEFAULT_COMPLEX_MAP_KEYS, 
        DEFAULT_JSON_NON_EXECUTABLE, 
        DEFAULT_ESCAPE_html,
        DEFAULT_PRETTY_PRINT, 
        DEFAULT_LENIENT,
        DEFAULT_SPECIALIZE_FLOAT_VALUES,
        LongSerializationPolicy.DEFAULT, 
        null, 
        DateFormat.DEFAULT, DateFormat.DEFAULT,
        Collections.<TypeAdapterFactory>emptyList(), Collections.<TypeAdapterFactory>emptyList(),
        Collections.<TypeAdapterFactory>emptyList());
  }

这么多参数,其实我自己看着也挺懵逼的,还是那句老话,等到用到的时候,我们再去看它们吧。但是有一段代码需要注意:

    // 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);

    // users' type adapters
    factories.addAll(factoriesToBeAdded);

    // type adapters for basic platform types
    factories.add(TypeAdapters.STRING_FACTORY);
    factories.add(TypeAdapters.INTEGER_FACTORY);
    factories.add(TypeAdapters.BOOLEAN_FACTORY);
    factories.add(TypeAdapters.BYTE_FACTORY);
    factories.add(TypeAdapters.SHORT_FACTORY);
    TypeAdapter<Number> longAdapter = longAdapter(longSerializationPolicy);
    factories.add(TypeAdapters.newFactory(long.class, Long.class, longAdapter));
    factories.add(TypeAdapters.newFactory(double.class, Double.class,
            doubleAdapter(serializeSpecialFloatingPointValues)));
    factories.add(TypeAdapters.newFactory(float.class, Float.class,
            floatAdapter(serializeSpecialFloatingPointValues)));
    factories.add(TypeAdapters.NUMBER_FACTORY);
    factories.add(TypeAdapters.ATOMIC_INTEGER_FACTORY);
    factories.add(TypeAdapters.ATOMIC_BOOLEAN_FACTORY);
    factories.add(TypeAdapters.newFactory(AtomicLong.class, atomicLongAdapter(longAdapter)));
    factories.add(TypeAdapters.newFactory(AtomicLongArray.class, atomicLongArrayAdapter(longAdapter)));
    factories.add(TypeAdapters.ATOMIC_INTEGER_ARRAY_FACTORY);
    factories.add(TypeAdapters.CHARACTER_FACTORY);
    factories.add(TypeAdapters.STRING_BUILDER_FACTORY);
    factories.add(TypeAdapters.STRING_BUFFER_FACTORY);
    factories.add(TypeAdapters.newFactory(BigDecimal.class, TypeAdapters.BIG_DECIMAL));
    factories.add(TypeAdapters.newFactory(BigInteger.class, TypeAdapters.BIG_INTEGER));
    factories.add(TypeAdapters.URL_FACTORY);
    factories.add(TypeAdapters.URI_FACTORY);
    factories.add(TypeAdapters.UUID_FACTORY);
    factories.add(TypeAdapters.CURRENCY_FACTORY);
    factories.add(TypeAdapters.LOCALE_FACTORY);
    factories.add(TypeAdapters.INET_ADDRESS_FACTORY);
    factories.add(TypeAdapters.BIT_SET_FACTORY);
    factories.add(DateTypeAdapter.FACTORY);
    factories.add(TypeAdapters.CALENDAR_FACTORY);
    factories.add(TimeTypeAdapter.FACTORY);
    factories.add(SqlDateTypeAdapter.FACTORY);
    factories.add(TypeAdapters.TIMESTAMP_FACTORY);
    factories.add(ArrayTypeAdapter.FACTORY);
    factories.add(TypeAdapters.CLASS_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在初始化时,内部就注册了大量的了 TypeAdapter,即根据不同的类型,选择自定义的TypeAdapter进行属性的解析和注入。

2. 源码分析

String jsonStr = "{'name' : 'Steven', 'age' : 18, 'address' : []}";
Person p = new Gson().fromJson(jsonStr, Person.class);

现在来看一下源码:

 public <T> T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException {
    Object object = fromJson(json, (Type) classOfT);
    return Primitives.wrap(classOfT).cast(object);
  }

直接深入:

  public <T> T fromJson(String json, Type typeOfT) throws JsonSyntaxException {
    if (json == null) {
      return null;
    }
    StringReader reader = new StringReader(json);
    T target = (T) fromJson(reader, typeOfT);
    return target;
  }

这里直接出现了StringReader,先说明它的作用,还是直接深入fromJson()源码:

  public <T> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
    
    try {
    
      TypeToken<T> typeToken = (TypeToken<T>) TypeToken.get(typeOfT);
      TypeAdapter<T> typeAdapter = getAdapter(typeToken);
      T object = typeAdapter.read(reader);
      return object;
      
    } catch (EOFException e) {}
    

直接看 getAdapter():

public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
    // 代码省略....只拿关键代码

    // 如果存在缓存 直接从缓存中取
    TypeAdapter<?> cached = typeTokenCache.get(type == null ? NULL_KEY_SURROGATE : type);
    if (cached != null) {
      return (TypeAdapter<T>) cached;
    }

    try {
  
     //遍历factory
      for (TypeAdapterFactory factory : factories) {
        TypeAdapter<T> candidate = factory.create(this, type);
        if (candidate != null) {
          call.setDelegate(candidate);
          typeTokenCache.put(type, candidate);
          return candidate;
        }
      }
    }
   
  }

其实最主要的就是遍历factories, 在factory.create()中获取到我们的candidate候选者,如果候选者为空,则继续遍历,直到找到合适的为止。

这里存在34个factory,我们大致看一下是根据什么判断候选者是否为空了吧,来一个简单的:TypeAdapters.STRING_FACTOR

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) {
        return typeToken.getRawType() == type ? (TypeAdapter<T>) typeAdapter : null;
      } 

由于此时我们的type类型是Person类型,所有返回为null,继续下一个,重复这个逻辑,到了最后只剩下ReflectiveTypeAdapterFactory这个工厂类,看名字就知道这个反射类型的工具类:

  @Override public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) {
    Class<? super T> raw = type.getRawType();

    ObjectConstructor<T> constructor = constructorConstructor.get(type);
    return new Adapter<T>(constructor, getBoundFields(gson, type, raw));
  }


可以看到,这里无论如何都是会返回一个Adapter的,这就是我们默认兜底的策略,现在来了最重要的一个方法了:getBoundFields,来看看主要是干了些什么吧:

private Map<String, BoundField> getBoundFields(Gson context, TypeToken<?> type, Class<?> raw) {
    Map<String, BoundField> result = new LinkedHashMap<String, BoundField>();

    Type declaredType = type.getType();
    while (raw != Object.class) {
      //通过反射 获取到 class 的属性
      Field[] fields = raw.getDeclaredFields();
      
      for (Field field : fields) {
        BoundField previous = null;
        for (int i = 0, size = fieldNames.size(); i < size; ++i) {
          String name = fieldNames.get(i);
          BoundField boundField = createBoundField(context, field, name, TypeToken.get(fieldType), serialize, deserialize);
          result.put(name, boundField);
        }
      }
      
      type = TypeToken.get($Gson$Types.resolve(type.getType(), raw, raw.getGenericSuperclass()));
      raw = type.getRawType();
    }
    
    return result;
  }

这段代码主要做了以下功能:

  1. 获取Class的所有属性;
  2. 将每一个属性转化为的BoundField,并保存;
  3. 获取父类的Class对象,依照步骤1,2;
  4. 返回包含所有BoundField的对象。

好了,现在我们回到代码入口处:

  public <T> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
    
    try {
    
      TypeToken<T> typeToken = (TypeToken<T>) TypeToken.get(typeOfT);
      TypeAdapter<T> typeAdapter = getAdapter(typeToken);
      T object = typeAdapter.read(reader);
      return object;
      
    } catch (EOFException e) {}
    

此时的typeAdapter就是我们已经确定的ReflectiveTypeAdapterFactory,现在直接看read(reader)方法了:

    @Override public T read(JsonReader in) throws IOException {
     
      // 1. 初始化对象
      T instance = constructor.construct();

      try {
        in.beginObject();
        
        while (in.hasNext()) {
        
          //2. 获取字符串中的名称     
          String name = in.nextName();
          
          //3. 在刚才反射集合中通过名称查找 BoundField
          BoundField field = boundFields.get(name);
          if (field == null || !field.deserialized) {
            in.skipValue();
          } else {
          
            // 4. 读取数据,赋值给对象指定属性
            field.read(in, instance);
          }
        }
        
      } catach(Exception e){}
      
      in.endObject();
      return instance;
    }

read(reader)方法中,基本的代码已经注释了,现在最复杂的就是注释4,读取数据,然后赋值给对象的指定属性。好了,我们直接上代码:

  //注释1
  final TypeAdapter<?Gson源码解析

GSON源码解析

解析工具Gson源码读后感,真实项目开发经验总结

Gson解析Json

Gson全解析(下)-Gson性能分析

Retrofit Gson解析空字符串的问题