Gson 源码解析

本文详细探讨了Gson库的源码解析过程,从Gson.fromJson()方法入手,分析了如何通过getAdapter()获取匹配的TypeAdapter,特别是聚焦于ReflectiveTypeAdapterFactory中的反射解析原理。文章还提到了JsonReader中的关键函数doPeek()及其调用链,并简单介绍了nextNonWhitespace()和fillBuffer()。最后,作者分享了自己实现的一个简单Json解析器的GitHub链接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Gson使用方法:
Gson.fromJson(String json, Class clazz)
所以从 fromJson 开始解析

Gson.java

fromJson() 有多个重载函数,最终都会调用下面这个

  public <T> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
    boolean isEmpty = true;
    boolean oldLenient = reader.isLenient(); // lenient : 宽容
    reader.setLenient(true);
    try {
      reader.peek(); // 返回下一个标记 但不会消耗, 应该是为了看看是否抛出异常
      isEmpty = false;
      // TypeToken 就是对 Type 的一个封装
      TypeToken<T> typeToken = (TypeToken<T>) TypeToken.get(typeOfT); // 根据Type获取对应的 TypeToken
      TypeAdapter<T> typeAdapter = getAdapter(typeToken); // 获取对应的 adapter
      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) {
      throw new JsonSyntaxException(e);
    } finally {
      reader.setLenient(oldLenient);
    }
  }
  public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
    // 省略部分代码
    try {
      FutureTypeAdapter<T> call = new FutureTypeAdapter<T>();
      threadCalls.put(type, call);

      // 遍历所有的 TypeAdapterFactory ,找到匹配的 Adapter
      // TypeAdapterFactory.create() 会返回对应的 TypeAdapter, 如果 TypeToken 不符合的话返回 null
      for (TypeAdapterFactory factory : factories) {
        TypeAdapter<T> candidate = factory.create(this, type);
        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();
      }
    }
  }

上面 getAdapter 代码中会遍历存储 TypeAdapterFactory 的 factories 来找匹配的 TypeAdapter
那 factories 是什么时候添加的?

Gson( ... 省略参数 ... ) {

    // 省略部分代码
    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);

    // 添加用户自定义的 typeadapter
    factories.addAll(typeAdapterFactories);

    // 添加基本类型的 tpyeAdatper
    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);
    // 后面还有很多,此处省略 ...

    // type adapters for composite and user-defined types
    factories.add(new CollectionTypeAdapterFactory(constructorConstructor));
    factories.add(new MapTypeAdapterFactory(constructorConstructor, complexMapKeySerialization));
    factories.add(new JsonAdapterAnnotationTypeAdapterFactory(constructorConstructor));
    factories.add(TypeAdapters.ENUM_FACTORY);
    // 用于反射的 typeAdapter
    factories.add(new ReflectiveTypeAdapterFactory(
        constructorConstructor, fieldNamingStrategy, excluder));

    this.factories = Collections.unmodifiableList(factories);
  }

我们再回到 fromJson() 中,刚才分析到了 getAdapter()
接下来继续

      T object = typeAdapter.read(reader);

找到匹配的 typeAdapter 就会调用其 read() 函数进行解析,此处我们着重分析 Gson 的反射实现原理,所以此处查看 ReflectiveTypeAdapterFactory 中 adapter 的 read() 实现

ReflectiveTypeAdapterFactory.java

在 ReflectiveTypeAdapterFactory 中有内部类 Adapter 如下,真正调用的是其 read() 函数

 public static final class Adapter<T> extends TypeAdapter<T> {

    @Override public T read(JsonReader in) throws IOException {
      if (in.peek() == JsonToken.NULL) {
        in.nextNull();
        return null;
      }

      T instance = constructor.construct(); // 反射创建实例

      try {
        in.beginObject(); // 开始读Object,会设置 stack[stackSize ++] = JsonScope.EMPTY_OBJECT 后面 in.doPeek() 会用到
        while (in.hasNext()) { // 调用 doPeek()
          String name = in.nextName(); // 获取变量名
          BoundField field = boundFields.get(name);
          if (field == null || !field.deserialized) {
            in.skipValue();
          } else {
            field.read(in, instance); // 给变量设值 调用 field.set() 设值 其中会调用 adapter.read() 递归
          }
        }
      } catch (...) {
      // 省略代码
      }

      in.endObject();
      return instance; // 返回解析到的对象实例
    }
  }

至此整体大概的解析完成,总结一下整体流程,附上流程图
gson

最后介绍一些比较重要的函数
上述代码中的 in.beginObject() in.hasNext() in.nextName() in.skipValue() 都会调用 Reader 中的 doPeek(),其他的代码也会调用 doPeek() 所以这个函数非常重要,接下来解析此函数

JsonReader.java
- doPeek()

  int doPeek() throws IOException {
    // 每次调用 beginXXX 的时候都会调用 stack[stackSize ++] = JsonScope.XXX
    int peekStack = stack[stackSize - 1]; // 获取 stack 顶部标志
    if (peekStack == JsonScope.EMPTY_ARRAY) {
      stack[stackSize - 1] = JsonScope.NONEMPTY_ARRAY;
    } else if (peekStack == JsonScope.NONEMPTY_ARRAY) {
      int c = nextNonWhitespace(true); // 获取下一个非空字符
      switch (c) { // 解析字符,下面的代码和这个类似,就省略了
      case ']':
        return peeked = PEEKED_END_ARRAY;
      case ';':
        checkLenient(); // fall-through
      case ',':
        break;
      default:
        throw syntaxError("Unterminated array");
      }
    } else if ( ... ) {
      // ...
    }

    int c = nextNonWhitespace(true);
    switch (c) {
    // ...
    }

    int result = peekKeyword(); 
    if (result != PEEKED_NONE) {
      return result;
    }

    result = peekNumber();
    if (result != PEEKED_NONE) {
      return result;
    }

    return peeked = PEEKED_UNQUOTED;
  }

peek() 函数内部基本上是对 doPeek() 的调用

JsonReader.java
- nextNonWhitespace()

  private int nextNonWhitespace(boolean throwOnEof) throws IOException {

    char[] buffer = this.buffer;
    int p = pos; // pos 表示当前解析的位置
    int l = limit; // limit 表示最后位置
    while (true) {
      if (p == l) { // 说明 buffer 已经读完了
        pos = p;
        if (!fillBuffer(1)) { // 从 instream 中填充 buffer, 参数表示最少需要填充多少, 返回表示是否能满足最少需要的
          break;
        }
        p = pos; // 更新数据
        l = limit;
      }

      int c = buffer[p++]; // 获取当前字符
      if (c == '\n') {
        lineNumber++;
        lineStart = p; // 当前行从哪个位置开始
        continue;
      } else if (c == ' ' || c == '\r' || c == '\t') { // 过滤空格等字符
        continue;
      }

      if (c == '/') { // 读取 /**/ 和 // 的注释
        pos = p;
        if (p == l) {
          pos--; // push back '/' so it's still in the buffer when this method returns
          boolean charsLoaded = fillBuffer(2);
          pos++; // consume the '/' again
          if (!charsLoaded) {
            return c;
          }
        }

        checkLenient(); // 检测兼容性,先忽略
        char peek = buffer[pos];
        switch (peek) {
        case '*': // 读取 "/**/" 注释
          pos++;
          if (!skipTo("*/")) {
            throw syntaxError("Unterminated comment");
          }
          p = pos + 2;
          l = limit;
          continue;

        case '/': // 读取 "//" 注释
          // skip a // end-of-line comment
          pos++;
          skipToEndOfLine();
          p = pos;
          l = limit;
          continue;

        default:
          return c;
        }
      } else if (c == '#') { // 读取 '#' 的注释, 直接跳到下一行
        pos = p;
        checkLenient();
        skipToEndOfLine();
        p = pos;
        l = limit;
      } else { // 返回解析到的字符,并重置pos
        pos = p;
        return c;
      }
    }
    if (throwOnEof) {
      throw new EOFException("End of input"
          + " at line " + getLineNumber() + " column " + getColumnNumber());
    } else {
      return -1;
    }
  }

在 nextNonWhitespace 中会调用到 fillBuffer() 来填充,接下来看一下 fillBuffer() 的实现

  private boolean fillBuffer(int minimum) throws IOException {
    char[] buffer = this.buffer;
    lineStart -= pos;
    if (limit != pos) {
      limit -= pos;
      System.arraycopy(buffer, pos, buffer, 0, limit); // 覆盖之前解析过的字符
    } else {
      limit = 0;
    }

    pos = 0;
    int total;
    while ((total = in.read(buffer, limit, buffer.length - limit)) != -1) { 
      // 从 reader 中读取字符填满 buffer
      limit += total;

      // 如果是第一次读取的话,要保证首个字符不是非法字符
      if (lineNumber == 0 && lineStart == 0 && limit > 0 && buffer[0] == '\ufeff') {
        pos++;
        lineStart++;
        minimum++;
      }

      if (limit >= minimum) { // 可以满足需求的字符数量
        return true;
      }
    }
    return false;
  }

这样 Gson 使用反射来解析 json 大体上解析完了,接下来自己实现了一个简单的Json解析器,地址如下:https://github.com/5A59/JsonParser

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值