Gson源码解析

这里写自定义目录标题

  • 遇到的问题
  • Gson
    • 版本
    • Json 转 对象
  • 总结

遇到的问题

在使用Gson将 Json字符创 转化为 Java 对象的时候,由于没有给字段加上@Serializable 注解,导致在混淆前运行正常,混淆后运行错误,所以跟了一下源码,就有了这篇文章。

Gson

版本

2.8.5

Json 转 对象

将Json字符串转化为数据类实例,可以调用 Gson.fromJson() ,所以我们从 fromJson() 方法这个入口开始。

进入 fromJson() 方法后,内部又调用了多个重载方法()

public <T> T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException {
	// 调用 fromJson 重载方法
    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;
  }
public <T> T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException {
    JsonReader jsonReader = newJsonReader(json);
    T object = (T) fromJson(jsonReader, typeOfT);
    assertFullConsumption(object, jsonReader);
    return object;
  }
public <T> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
    boolean isEmpty = true;
    boolean oldLenient = reader.isLenient();
    reader.setLenient(true);
    try {
      // 如果 json字符串长度为0,则 peek方法会抛出 EOFException异常
      reader.peek();
      isEmpty = false;
      // 将 Type 作为参数,创建一个 TypeToken 对象
      TypeToken<T> typeToken = (TypeToken<T>) TypeToken.get(typeOfT);
      // 通过 TypeToken 创建一个 TypeAdapter
      TypeAdapter<T> typeAdapter = getAdapter(typeToken);
      T object = typeAdapter.read(reader);
      return object;
    } catch (EOFException e) {
      /*
       * For compatibility with JSON 1.5 and earlier, we return null for empty
       * documents instead of throwing.
       */
      if (isEmpty) {
        return null;
      }
      throw new JsonSyntaxException(e);
    } catch (IllegalStateException e) {
      throw new JsonSyntaxException(e);
    } catch (IOException e) {
      // TODO(inder): Figure out whether it is indeed right to rethrow this as JsonSyntaxException
      throw new JsonSyntaxException(e);
    } finally {
      reader.setLenient(oldLenient);
    }
  }

最终是到最后一个方法 fromJson(JsonReader reader, Type typeOfT) 来得到 Java 对象的,这个方法里有个比较关键的地方其实就两步,第一步是调用 getAdapter() 获取 TypeAdapter,第二部是调用该 TypeAdapter 的 read() 方法得到我们想要的 数据类实例。

我们先看一下第一步 getAdapter() 方法:

public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
	// 先从缓存中获取 TypeAdapter
    TypeAdapter<?> cached = typeTokenCache.get(type == null ? NULL_KEY_SURROGATE : type);
    if (cached != null) {
      return (TypeAdapter<T>) cached;
    }

    //......

    try {
      FutureTypeAdapter<T> call = new FutureTypeAdapter<T>();
      threadCalls.put(type, call);

      for (TypeAdapterFactory factory : factories) {
        // 遍历 factories 创建 TypeAdapter
        TypeAdapter<T> candidate = factory.create(this, type);
        if (candidate != null) {
          // 如果 candidate 不为空,说明创建成功
          // 用 FutureTypeAdapter 包装 TypeAdapter
          call.setDelegate(candidate);
          // 将该 TypeAdapter 存入缓存
          typeTokenCache.put(type, candidate);
          return candidate;
        }
      }
      throw new IllegalArgumentException("GSON cannot handle " + type);
    } finally {
      threadCalls.remove(type);

      if (requiresThreadLocalCleanup) {
        calls.remove();
      }
    }
  }

我们可以看到 TypeAdapter 是通过 工厂方法创建的,这里的 factories 就是个创建 TypeAdapter 的工厂集合,这里举例几个工厂:
① Object 类型:当数据类型 是 Object 时,使用此工厂创建 TypeAdapter

public final class ObjectTypeAdapter extends TypeAdapter<Object> {
  public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
    @SuppressWarnings("unchecked")
    @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
      if (type.getRawType() == Object.class) {
        return (TypeAdapter<T>) new ObjectTypeAdapter(gson);
      }
      return null;
    }
  };
}

②基本数据类型及其包装类型:

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) {
      Class<? super T> rawType = typeToken.getRawType();
      return (rawType == unboxed || rawType == boxed) ? (TypeAdapter<T>) typeAdapter : null;
    }
    @Override public String toString() {
      return "Factory[type=" + boxed.getName()
          + "+" + unboxed.getName() + ",adapter=" + typeAdapter + "]";
    }
  };
}

③Object 类型的子类

public final class ReflectiveTypeAdapterFactory implements TypeAdapterFactory {
    @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
      ObjectConstructor<T> constructor = constructorConstructor.get(type);
      // 调用 getBoundFields 得到 BoundField map集合
      // 用 constructor 和 BoundField 创建 Adapter(内部类)
      return new Adapter<T>(constructor, getBoundFields(gson, type, raw));
    }
    
    public static final class Adapter<T> extends TypeAdapter<T> {
    private final ObjectConstructor<T> constructor;
    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;
      }

      T instance = constructor.construct();

      try {
        in.beginObject();
        while (in.hasNext()) {
          String name = in.nextName();
          BoundField field = boundFields.get(name);
          if (field == null || !field.deserialized) {
            in.skipValue();
          } else {
            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();
    }
  }
  }

一般情况下,我们自己编写的数据类,使用的是第三种工厂创建得到 TypeAdapter。
这个工厂有一个create() 方法,create() 中先通过 constructorConstructor.get() 得到一个 ObjectConstructor 构建器对象,很明显这个 ObjectConstructor 构建器就是用来创建数据类实例的。这里最终会通过 newDefaultConstructor() 得到一个默认的构建器,该构建器的作用就是使用反射调用类的无参构造函数来得到数据类实例。

得到 ObjectConstructor 后,紧接着调用 getBoundFields 得到 BoundField map集合, 用 ObjectConstructor 和 BoundField 创建 Adapter(该 Adapter 是 ReflectiveTypeAdapterFactory 的内部类)
我们先看一下 newDefaultConstructor() 得到的默认构建器

private <T> ObjectConstructor<T> newDefaultConstructor(Class<? super T> rawType) {
  try {
    final Constructor<? super T> constructor = rawType.getDeclaredConstructor();
    if (!constructor.isAccessible()) {
      accessor.makeAccessible(constructor);
    }
    return new ObjectConstructor<T>() {
      @SuppressWarnings("unchecked") // T is the same raw type as is requested
      @Override public T construct() {
        try {
          Object[] args = null;
          //使用反射调用无参构造函数来得到数据类实例
          return (T) constructor.newInstance(args);
        } catch (InstantiationException e) {
          // TODO: JsonParseException ?
          throw new RuntimeException("Failed to invoke " + constructor + " with no args", e);
        } catch (InvocationTargetException e) {
          // TODO: don't wrap if cause is unchecked!
          // TODO: JsonParseException ?
          throw new RuntimeException("Failed to invoke " + constructor + " with no args",
              e.getTargetException());
        } catch (IllegalAccessException e) {
          throw new AssertionError(e);
        }
      }
    };
  } catch (NoSuchMethodException e) {
    return null;
  }
}

得到 ObjectConstructor 后,我们看 getBoundFields() 方法

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();
  while (raw != Object.class) {
      // 获取数据类型的所有字段
    Field[] fields = raw.getDeclaredFields();
    for (Field field : fields) {
      boolean serialize = excludeField(field, true);
      boolean deserialize = excludeField(field, false);
      if (!serialize && !deserialize) {
        continue;
      }
      accessor.makeAccessible(field);
      // 获取字段的 Type 类型
      Type fieldType = $Gson$Types.resolve(type.getType(), raw, field.getGenericType());
      List<String> fieldNames = getFieldNames(field);
      BoundField previous = null;
      for (int i = 0, size = fieldNames.size(); i < 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);
        BoundField replaced = result.put(name, boundField);
        if (previous == null) previous = replaced;
      }
      if (previous != null) {
        throw new IllegalArgumentException(declaredType
            + " declares multiple JSON fields named " + previous.name);
      }
    }
    type = TypeToken.get($Gson$Types.resolve(type.getType(), raw, raw.getGenericSuperclass()));
    raw = type.getRawType();
  }
  return result;
}

getBoundFields() 方法的作用就是,反射获取数据类的所有字段,并获取字段名称,然后为每个字段创建BoundField。
我们先看看获取字段名称的方法 getFieldNames()

private List<String> getFieldNames(Field f) {
  SerializedName annotation = f.getAnnotation(SerializedName.class);
  if (annotation == null) {
    // 如果字段没有加 SerializedName 注解,则直接获取字段名称
    String name = fieldNamingPolicy.translateName(f);
    return Collections.singletonList(name);
  }
  // 如果字段加了 SerializedName 注解,则获取该注解的 value
  String serializedName = annotation.value();
  String[] alternates = annotation.alternate();
  if (alternates.length == 0) {
    return Collections.singletonList(serializedName);
  }

  List<String> fieldNames = new ArrayList<String>(alternates.length + 1);
  fieldNames.add(serializedName);
  for (String alternate : alternates) {
    fieldNames.add(alternate);
  }
  return fieldNames;
}

很重要的一点,如果字段加了 @Serializable 注解,则会获取该注解的 value值,如果没有加 @Serializable 注解, 则直接获取字段名。
然后我们再看看创建 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());
  // special casing primitives here saves ~5% on Android...
  JsonAdapter annotation = field.getAnnotation(JsonAdapter.class);
  TypeAdapter<?> mapped = null;
  if (annotation != null) {
    mapped = jsonAdapterFactory.getTypeAdapter(
        constructorConstructor, context, fieldType, annotation);
  }
  final boolean jsonAdapterPresent = mapped != null;
  if (mapped == null) mapped = context.getAdapter(fieldType);

  final TypeAdapter<?> typeAdapter = mapped;
  return new ReflectiveTypeAdapterFactory.BoundField(name, serialize, deserialize) {
    @SuppressWarnings({"unchecked", "rawtypes"}) // the type adapter and field type always agree
    @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 {
      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 的作用就是对指定字段进行读写。
这个时候,我们就通过 ObjectConstructor 和 BoundField 创建得到了 TypeAdapter。

public static final class Adapter<T> extends TypeAdapter<T> {
  private final ObjectConstructor<T> constructor;
  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;
    }
    // 通过上面创建的 ObjectConstructor 创建一个数据类对象
    T instance = constructor.construct();

    try {
      in.beginObject();
      // 将 json 的值写入到对象中
      while (in.hasNext()) {
        String name = in.nextName(); // 获取 json 的键
        BoundField field = boundFields.get(name); // 通过 name 获取对象的 boundField
        if (field == null || !field.deserialized) {
          in.skipValue();
        } else {
          // 调用 boundField 的 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();
  }
}

fromJson 得到 TypeAdapter 后,会调用 TypeAdapter 的 read() 方法,得到一个 数据类实例。
read() 方法上面已经给出了,就是先用 ObjectConstructor 创建数据类实例,然后通过每个字段的BoundField 的 read() 方法写入字段的值。

总结

开头的问题已经得到答案了,如果字段加了 @Serializable 注解,则会获取该注解的 value值作为映射的 key,如果没有加 @Serializable 注解, 则直接获取字段名作为映射的 key。而如果没有加注解,混淆后的字段名就是 abcd,导致混淆后无法得到正确结果。

你可能感兴趣的:(android,java,Gson,Android,Java,Json)