Gson源码解析

purplefrog 发布于3年前

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; // 返回解析到的对象实例
    }
  }

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

 

最后介绍一些比较重要的函数
上述代码中的 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解析器,地址如下:Json解析器

 

查看原文: Gson源码解析