资讯专栏INFORMATION COLUMN

追踪解析Gson源码(2)

shiguibiao / 2097人阅读

摘要:接上篇三和在进行的序列化和反序列化源码解析之前先了解一下其主体工具类。是中用于序列化的主体。同时为了兼顾性能做了很多有意思的设计,比如获取适配器的时候的双缓存设计,应该是为了提高解析器的复用效率,具体有待研究。

接上篇 三 JsonReader 和 JsonWriter

在进行 json 的序列化和反序列化源码解析之前先了解一下其主体工具类。

1 JsonReader

JsonReader 是 Gson 中用于 json 反序列化的主体。

在 Gson 包中可以不使用 Gson 门面而多带带使用 JsonReader 进行 json 的反序列化:

public static void main(String[] args){
    //json 字符串
    String json = "{"name":"zhangsan","age":18}";
    //使用 StringReader 包装字符串
    StringReader strReader = new StringReader(json);
    //使用 JsonReader 包装 StringReader
    JsonReader jsonReader = new JsonReader(strReader);
    //创建一个参数均为空的目标对象
    Person p = new Person();
    try {
        //beginObject(...) 方法用于告诉 jsonReader 开始读取一个 object
        jsonReader.beginObject();
        //while 循环读取
        while(jsonReader.hasNext()){
            //读取一个 json 的 key 值
            String name = jsonReader.nextName();
            switch (name){
                case "name": 
                    p.setName(jsonReader.nextString()); //读取一个 String 作为 value,存入对象中
                    break;
                case "age": 
                    p.setAge(jsonReader.nextInt()); //读取一个 int 作为 value,存入对象中
                    break;
            }
        }
        jsonReader.endObject();
    } catch (IOException e) {
        e.printStackTrace();
    }
    System.out.println("名字:" + p.getName());
    System.out.println("年龄:"  +p.getAge())
}

JsonReader 的构造方法:

//JsonReader.class
public JsonReader(Reader in) {
    if (in == null) {
        throw new NullPointerException("in == null");
    }
    //传入的 Reader 中保存着要读取的 json 主体 
    //此处比较常用的是 StringReader,但是也可以是 FileReader 等其它 Reader 接口的实现类
    this.in = in;
}

JsonReader 仅此一个构造方法,创建对象均调用此方法。

先来看一下 JsonReader 中非常重要的一个非公开方法 doPeek():

//JsonReader.class
int doPeek() throws IOException {
    //stack 是一个定义在 JsonReader 中的 int 数组,作为 JsonReader 的指令集存在,用于控制变量 peeked 的状态
    //在 JsonReader 初始化的时候会将 stack 的第一个元素变成6,其余均为0
    //6的意思根据官方注释为 "No object or array has been started"(还没开始读取对象或列表)
    //6作为常量保存在 JsonScope 中,JsonScope 中还保存了很多代表指令的常量,下列会用到
    //stackSize 是 stack 的有效元素计数器,初始化时 stackSize = 1,即只有第一个元素是有效的
    int peekStack = stack[stackSize - 1];
    
    //JsonScope.EMPTY_ARRAY = 1
    if (peekStack == JsonScope.EMPTY_ARRAY) {
        //JsonScope.NONEMPTY_ARRAY = 2
        stack[stackSize - 1] = JsonScope.NONEMPTY_ARRAY;
    } else if (peekStack == JsonScope.NONEMPTY_ARRAY) {
        //在第一次调用 nextNonWhitespace(true) 方法的时候,json 字符串会被转存为一个 char 数组
        //该方法以 int 值的形式返回下一个要解析的 char 对象
        int c = nextNonWhitespace(true);
        switch (c) {
            case "]":
                //peeked 是 JsonReader 中最重要的用来状态控制的 int 变量
                //peeker 和 stack 会协同控制 JsonReader 的逻辑行为
                return peeked = PEEKED_END_ARRAY; //PEEKED_END_ARRAY = 4
            case ";":
                 //检查标准协议选项,json 标准中的符号没有分号
                //所以在 lenient = false 的时候就会报错
                checkLenient();
            case ",":
                break;
            default:
                throw syntaxError("Unterminated array");
        }
        //JsonScope.EMPTY_OBJECT = 3,JsonScope.NONEMPTY_OBJECT = 5
    } else if (peekStack == JsonScope.EMPTY_OBJECT || peekStack == JsonScope.NONEMPTY_OBJECT) {
        //JsonScope.DANGLING_NAME = 4
        stack[stackSize - 1] = JsonScope.DANGLING_NAME;
        if (peekStack == JsonScope.NONEMPTY_OBJECT) {
            int c = nextNonWhitespace(true);
            switch (c) {
                case "}":
                    return peeked = PEEKED_END_OBJECT; //PEEKED_END_OBJECT = 2
                case ";":
                    checkLenient();
                case ",":
                    break;
                default:
                    throw syntaxError("Unterminated object");
            }
        }
        int c = nextNonWhitespace(true);
        switch (c) {
            case """:
                return peeked = PEEKED_DOUBLE_QUOTED_NAME; //PEEKED_DOUBLE_QUOTED_NAME = 13
            case """:
                checkLenient();
                return peeked = PEEKED_SINGLE_QUOTED_NAME; //PEEKED_SINGLE_QUOTED_NAME = 12
            case "}":
                if (peekStack != JsonScope.NONEMPTY_OBJECT) {
                    return peeked = PEEKED_END_OBJECT;
                } else {
                    throw syntaxError("Expected name");
                }
            default:
                checkLenient();
                pos--;
                if (isLiteral((char) c)) {
                    return peeked = PEEKED_UNQUOTED_NAME; //PEEKED_UNQUOTED_NAME = 14
                } else {
                    throw syntaxError("Expected name");
                }
        }

    } else if (peekStack == JsonScope.DANGLING_NAME) {
        stack[stackSize - 1] = JsonScope.NONEMPTY_OBJECT;
        int c = nextNonWhitespace(true);
        switch (c) {
            case ":":
                break;
            case "=":
                checkLenient();
                //buffer 是储存 json 字符串的 char 数组
                //pos 是已经读取到字符的数量指针
                //limit 是 buffer 的可用部分的总长
                if ((pos < limit || fillBuffer(1)) && buffer[pos] == ">") {
                    pos++;
                }
                break;
            default:
                throw syntaxError("Expected ":"");
        }
        //JsonScope.EMPTY_DOCUMENT = 6
        //第一次进入方法的时候,会进入这个 if 语句中
    } else if (peekStack == JsonScope.EMPTY_DOCUMENT) {
        //检查标准化协议相关
        if (lenient) {
            consumeNonExecutePrefix();
        }
        //JsonScope.NONEMPTY_DOCUMENT = 7
        stack[stackSize - 1] = JsonScope.NONEMPTY_DOCUMENT;
    } else if (peekStack == JsonScope.NONEMPTY_DOCUMENT) {
        int c = nextNonWhitespace(false);
        if (c == -1) {
            return peeked = PEEKED_EOF;
        } else {
            checkLenient();
            pos--;
        }
        //JsonScope.CLOSED = 8
    } else if (peekStack == JsonScope.CLOSED) {
        throw new IllegalStateException("JsonReader is closed");
    }

    //在这里获取到了下一个要解析的 char 的 int 值
    int c = nextNonWhitespace(true);
    //进入 switch 去进行定位,定位到了之后修改 peeked 的状态
    switch (c) {
        case "]":
            if (peekStack == JsonScope.EMPTY_ARRAY) {
            return peeked = PEEKED_END_ARRAY;
            }
            
        case ";":
        case ",":
            if (peekStack == JsonScope.EMPTY_ARRAY || peekStack == JsonScope.NONEMPTY_ARRAY) {
            checkLenient();
            pos--;
            return peeked = PEEKED_NULL;
            } else {
            throw syntaxError("Unexpected value");
            }
        case """:
            checkLenient();
            return peeked = PEEKED_SINGLE_QUOTED;
        case """:
            return peeked = PEEKED_DOUBLE_QUOTED;
        case "[":
            return peeked = PEEKED_BEGIN_ARRAY;
        case "{":
            return peeked = PEEKED_BEGIN_OBJECT;
        default:
            pos--;
    }

    //peekKeyword() 方法会从 buffer 数组里获取下一个 char
    //然后根据这个字符判断下一个要处理的字符串是不是 true、false、null 等特殊字符
    //如果不是,会返回 result = PEEKED_NONE
    int result = peekKeyword();
    if (result != PEEKED_NONE) {
        //不等于 PEEKED_NONE,证明下一个确实是特殊字符
        return result;
    }

    //peekNumber() 方法和上述 peekKeyword() 方法很类似
    //用于判断下一个要处理的字符串是否是数字
    result = peekNumber();
    if (result != PEEKED_NONE) {
        return result;
    }

    //isLiteral(buffer[pos]) 用于判断下一个字符是否是特殊符
    //比如 换行符、井号、括号 等
    //如果是 换行符 的话这里就会抛出错误
    if (!isLiteral(buffer[pos])) {
        throw syntaxError("Expected value");
    }

    checkLenient();
    return peeked = PEEKED_UNQUOTED; //PEEKED_UNQUOTED = 10
}

方法虽然比较长,但是代码其实比较简单,本质上是根据 stack 指令去修改 peeked 的值,从而达到状态控制的效果。

再来看 beginObject() 方法:

//JsonReader.class
public void beginObject() throws IOException {
    int p = peeked;

    //初始化时 peeked = PEEKED_NONE
    //在 doPeek() 方法中会修改成 PEEKED_BEGIN_OBJECT,即开始一个 Object 的序列化
    if (p == PEEKED_NONE) {
          p = doPeek();
    }
    if (p == PEEKED_BEGIN_OBJECT) {
        //push(...) 方法会检查 stack 数组的容积,适时进行扩容,并把传入的指令存放到数组中
        //此处将 EMPTY_OBJECT 指令存入到 stack 中
        push(JsonScope.EMPTY_OBJECT);
        //将 peeked 状态初始化
        peeked = PEEKED_NONE;
    } else {
          throw new IllegalStateException("Expected BEGIN_OBJECT but was " + peek() + locationString());
    }
}

再来看 nextName() 方法:

//JsonReader.class
public String nextName() throws IOException {
    //老样子进行 peeked 的状态获取
    int p = peeked;
    if (p == PEEKED_NONE) {
      p = doPeek();
    }
    String result;
    
    //在这里通过 if 语句和 peeked 定位 json 的 key 是用单引号还是双引号包裹的
    //result 就是 key 的字符串
    if (p == PEEKED_UNQUOTED_NAME) { 
      result = nextUnquotedValue();
    } else if (p == PEEKED_SINGLE_QUOTED_NAME) {
      result = nextQuotedValue(""");
    } else if (p == PEEKED_DOUBLE_QUOTED_NAME) {
      result = nextQuotedValue(""");
    } else {
      throw new IllegalStateException("Expected a name but was " + peek() + locationString());
    }
    //将 peeked 状态初始化
    peeked = PEEKED_NONE;
    //pathNames 是一个用来储存所有 key 的字符串的数组
    pathNames[stackSize - 1] = result;
    return result;
}

nextQuotedValue(...) 方法里实际上是比较繁琐的字符串处理,在这里暂时不展开了。

hasNext() 和 nextString() 方法其实都和 nextName() 方法差不多,本质上都是根据 peeked 的值去进入不同的 if 语句来处理字符串。

2 JsonWriter

JsonWriter 是 Gson 中用于 json 序列化的主体。

和 JsonReader 一样,也可以不使用 Gson 门面而多带带使用 JsonWriter 进行 json 的序列化:

public static void main(String[] args){
    //组装 bean
    Person person = new Person();
    person.setName("zhangsan");
    person.setAge(18);

    //创建一个 StringWriter,本质是 StringBuffer 的封装
    StringWriter writer = new StringWriter();
    //用 JsonWriter 去封装 StringWriter
    JsonWriter jsonWriter = new JsonWriter(writer);
    try {
        //启动一个 object 的写入
        jsonWriter.beginObject();
        //写入 key-value
        jsonWriter.name("name").value(person.getName());
        jsonWriter.name("age").value(person.getAge());
        //结束命令
        jsonWriter.endObject();
        //将 JsonWriter 里的数据存入到 StringWriter 中
        jsonWriter.flush();
    } catch (IOException e) {
        e.printStackTrace();
    }

    System.out.println(writer.toString());
}

JsonWriter 的构造方法:

//JsonWriter.class
public JsonWriter(Writer out) {
    if (out == null) {
        throw new NullPointerException("out == null");
    }
    this.out = out;
}

追踪一下 beginObject() 方法:

//JsonWriter.class
public JsonWriter beginObject() throws IOException {
    //这个方法主要的作用是在不同的 object 之间加逗号
    //如果是起始第一个 object 就不需要了,会直接跳过
    writeDeferredName();
    return open(EMPTY_OBJECT, "{");
}

继续追踪 open(...) 方法:

//JsonWriter.class
private JsonWriter open(int empty, String openBracket) throws IOException {
    //该方法会使用 stack 中最新的指令进行操作
    beforeValue();
    //push(...) 方法会检查 stack 数组的容积,适时进行扩容,并把传入的指令存放到数组中
    push(empty);
    //写入字符串
    out.write(openBracket);
    return this;
}

JsonWriter 中没有 JsonReader 中那么复杂的指令操作,所以没有引入 peeked 变量,仅仅使用 stack 数组来控制状态。

stack 的控制封装在 beforeValue() 方法中:

//JsonWriter.class
private void beforeValue() throws IOException {
    //peek() 方法会根据 stack 数组的指令获取到下一个要操作的字符类型
    switch (peek()) {
        case NONEMPTY_DOCUMENT:
            if (!lenient) {
            throw new IllegalStateException(
                "JSON must have only one top-level value.");
            }
        case EMPTY_DOCUMENT:
            //replaceTop(...) 方法会将 stack 最新的指令更新成传入的参数
            replaceTop(NONEMPTY_DOCUMENT);
            break;

        case EMPTY_ARRAY:
            replaceTop(NONEMPTY_ARRAY);
            //换行
            newline();
            break;
        case NONEMPTY_ARRAY:
            out.append(",");
            newline();
            break;
        case DANGLING_NAME:
            //separator 即为 ":" (冒号)
            out.append(separator);
            replaceTop(NONEMPTY_OBJECT);
            break;
        default:
            throw new IllegalStateException("Nesting problem.");
        }
}

来看一下 name(...) 方法:

//JsonWriter.class
public JsonWriter name(String name) throws IOException {
    if (name == null) {
      throw new NullPointerException("name == null");
    }
    if (deferredName != null) {
      throw new IllegalStateException();
    }
    if (stackSize == 0) {
      throw new IllegalStateException("JsonWriter is closed.");
    }
    //这一行代码中会暂时将传入的 name 参数保存在一个全局变量中,
    //所以 JsonWriter 在调用 value(...) 方法之前不能再调用 name(...) 方法了,不然在上方的判断中会报错
    deferredName = name;
    return this;
}

来看一下 value(...) 方法:

//JsonWriter.class
public JsonWriter value(String value) throws IOException {

    if (value == null) {
        //nullValue() 方法会在 value 值的地方存入一个 null
          return nullValue();
    }
    //这一方法会将 之前保存在 deferredName 中的字符串写入到 writer 中
    //方法中会处理加逗号、将 deferredName 变量清空等问题
    //核心是调用 string(...) 方法写入
    writeDeferredName();
    //更新 stack 指令
    beforeValue();
    //和上方写入 deferredName 一样,此处调用写入 value
    string(value);
    return this;
  }

总的来说 JsonWriter 比 JsonReader 简单,简要描述一下不过多展开。

四 JSON 字符串转 Bean

该 part 的起点:

Person person = gson.fromJson(json,Person.class);

追踪 fromJson(...) 方法:

//Gson.class
public  T fromJson(String json, Class classOfT) throws JsonSyntaxException {
    //将字符串转成 object 的主体方法
    //3.1
    Object object = fromJson(json, (Type) classOfT);

    return Primitives.wrap(classOfT).cast(object);
}

先来看一下上述的第二行代码:

return Primitives.wrap(classOfT).cast(object);

Primitives.wrap(...) 方法的实现:

//Primitives.class
public static  Class wrap(Class type) {
    //PRIMITIVE_TO_WRAPPER_TYPE 是一个 map 对象
    //$Gson$Preconditions.checkNotNull(...) 用来效验 type 不为空
    @SuppressWarnings("unchecked")
    Class wrapped = (Class) PRIMITIVE_TO_WRAPPER_TYPE.get(
        $Gson$Preconditions.checkNotNull(type));
    //如果 map 中不存在 type 为 key 的值,则返回 type,否则返回取到的 value
    return (wrapped == null) ? type : wrapped;
}

PRIMITIVE_TO_WRAPPER_TYPE 是一个定义在 Primitives 中的 map 对象:

//Primitives.class
private static final Map, Class> PRIMITIVE_TO_WRAPPER_TYPE;

PRIMITIVE_TO_WRAPPER_TYPE 中主要存放了 float、int、double 等原始类型的 class:

//Primitives.class
static {
    Map, Class> primToWrap = new HashMap, Class>(16);
    Map, Class> wrapToPrim = new HashMap, Class>(16);

    //以下代码是将原始类型和包装类型存入两个 map 的过程
    add(primToWrap, wrapToPrim, boolean.class, Boolean.class);
    add(primToWrap, wrapToPrim, byte.class, Byte.class);
    add(primToWrap, wrapToPrim, char.class, Character.class);
    add(primToWrap, wrapToPrim, double.class, Double.class);
    add(primToWrap, wrapToPrim, float.class, Float.class);
    add(primToWrap, wrapToPrim, int.class, Integer.class);
    add(primToWrap, wrapToPrim, long.class, Long.class);
    add(primToWrap, wrapToPrim, short.class, Short.class);
    add(primToWrap, wrapToPrim, void.class, Void.class);

    //Collections.unmodifiableMap(...) 返回一个只能阅读不能修改的 map
    //原始类型作为 key,包装类型作为 value
    PRIMITIVE_TO_WRAPPER_TYPE = Collections.unmodifiableMap(primToWrap);
    //包装类型作为 value,原始类型作为 key
    WRAPPER_TO_PRIMITIVE_TYPE = Collections.unmodifiableMap(wrapToPrim);
}

由此可见 Primitives.wrap(...) 本质上是判断传入的 type 是否是原始类型,如果是,则会转换成包装类型并返回。

至于 Primitives.wrap(classOfT).cast(object) 中的 cast(...),则是定义在 Class 中的方法:

//Class.class
@HotSpotIntrinsicCandidate
public T cast(Object obj) {
    //isInstance(...) 方法等价于关键词 instanceof
    //如果 obj 不为 null 且 不为该 Class 对象的子类,则会抛出错误
    if (obj != null && !isInstance(obj))
        throw new ClassCastException(cannotCastMsg(obj));
    return (T) obj;
}

代码比较简单,本质上就是强转类型。

再来看这行代码:

Object object = fromJson(json, (Type) classOfT);

追踪具体实现:

//Gson.class
public  T fromJson(String json, Type typeOfT) throws JsonSyntaxException {
    //非 null 判断
    if (json == null) {
      return null;
    }
    //StringReader 是一个 jdk 中存在的 String 和 Reader 的关联封装类
    StringReader reader = new StringReader(json);
    //主体功能实现方法
    T target = (T) fromJson(reader, typeOfT);
    //返回一个指定泛型的对象
    return target;
}

继续追踪重载方法:

//Gson.class
public  T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException {
    //初始化一个 JsonReader
    JsonReader jsonReader = newJsonReader(json);
    //主体功能实现方法
    T object = (T) fromJson(jsonReader, typeOfT);
    //在整个反序列化过程结束之前效验 jsonReader 的 peeked 的状态
    //如果 peeker 未处于结束状态,则会报错
    assertFullConsumption(object, jsonReader);
    return object;
}

继续追踪重载方法:

//Gson.class
public  T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
    boolean isEmpty = true;
    boolean oldLenient = reader.isLenient();
    //打开 reader 的标准化检验
    reader.setLenient(true);
    try {
        //此处相当于调用了一次 JsonReader 中的 doPeek() 方法
        reader.peek();
        isEmpty = false;
        //TypeToken 本质上是 Class 的增强封装类
        TypeToken typeToken = (TypeToken) TypeToken.get(typeOfT);
        //根据 TypeToken 获取对应的能够处理其类型的 TypeAdapter
        TypeAdapter typeAdapter = getAdapter(typeToken);
        //反射创建 object
        T object = typeAdapter.read(reader);
        return object;
    } catch (EOFException e) {
        if (isEmpty) {
            return null;
        }
        throw new JsonSyntaxException(e);
    } catch (IllegalStateException e) {
          throw new JsonSyntaxException(e);
    } catch (IOException e) {
        throw new JsonSyntaxException(e);
    } catch (AssertionError e) {
          throw new AssertionError("AssertionError (GSON " + GsonBuildConfig.VERSION + "): " + e.getMessage(), e);
    } finally {
          reader.setLenient(oldLenient);
    }
}

先来看一下 getAdapter(...) 方法:

//Gson.class
public  TypeAdapter getAdapter(TypeToken type) {
    //typeTokenCache 是 Gson 中的一个 map 对象,用于储存 TypeAdapter
    //typeTokenCache 是一个 Gson 中各个线程公用的一个缓存池
    TypeAdapter cached = typeTokenCache.get(type == null ? NULL_KEY_SURROGATE : type);
    if (cached != null) {
        //如果本身就有储存了,就直接返回
          return (TypeAdapter) cached;
    }

    //calls 是一个 ThreadLocal 对象
    //ThreadLocal 是 Gson 中单个线程使用的缓存池,在里面存入的对象会在 finally 代码块中清空掉
    Map, FutureTypeAdapter> threadCalls = calls.get();
    //判断是否需要清空 ThreadLocal
    boolean requiresThreadLocalCleanup = false;
    if (threadCalls == null) {
        threadCalls = new HashMap, FutureTypeAdapter>();
        calls.set(threadCalls);
        //这里存入了对象,所以需要清空 ThreadLocal
        requiresThreadLocalCleanup = true;
    }

    //如果存在对象,就会在这里取用出来并返回
    //FutureTypeAdapter 是一个门面模式的应用,其实本质是使用内部的 TypeAdapter 去处理业务
    //如果内部没有存入实际处理业务的 TypeAdapter,就会报错
    FutureTypeAdapter ongoingCall = (FutureTypeAdapter) threadCalls.get(type);
    if (ongoingCall != null) {
      return ongoingCall;
    }

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

        //这个方法的主体是这个 for 循环,用于从 Gson 初始化的时候储存的列表中获取到对应的 TypeAdapter
        for (TypeAdapterFactory factory : factories) {
            //TypeAdapter 的 create(...) 方法对于不是对应类型的参数会返回 null
            TypeAdapter candidate = factory.create(this, type);
            if (candidate != null) {
                //在此处会存入业务处理的 TypeAdapter
                call.setDelegate(candidate);
                //在此处存入公用缓存
                typeTokenCache.put(type, candidate);
                return candidate;
            }
        }
        throw new IllegalArgumentException("GSON (" + GsonBuildConfig.VERSION + ") cannot handle " + type);
    } finally {
        //清除 ThreadLocal 缓存
        threadCalls.remove(type);
        if (requiresThreadLocalCleanup) {
            calls.remove();
        }
    }
}

到此为止 json 的反序列化就基本完毕了.

五 Bean 转 JSON 字符串

该 part 的起点:

String json2 = gson.toJson(person);

追踪 toJson(...) 方法:

//Gson.class
public String toJson(Object src) {
    if (src == null) {
      return toJson(JsonNull.INSTANCE);
    }
    return toJson(src, src.getClass());
}

toJson(JsonNull.INSTANCE) 方法最后会输出一个 null 字符串,不多展开了。

继续来关注下方主要实现逻辑:

//Gson.class
public String toJson(Object src, Type typeOfSrc) {
    //新建一个 StringWriter
    StringWriter writer = new StringWriter();
    //主要逻辑
    toJson(src, typeOfSrc, writer);
    //返回
    return writer.toString();
}

继续追踪主要逻辑方法:

//Gson.class
public void toJson(Object src, Type typeOfSrc, Appendable writer) throws JsonIOException {
    try {
        //这里将 StringWriter 包装成了 JsonWriter
        JsonWriter jsonWriter = newJsonWriter(Streams.writerForAppendable(writer));
        //主要逻辑
        toJson(src, typeOfSrc, jsonWriter);
    } catch (IOException e) {
          throw new JsonIOException(e);
    }
}

继续追踪主要逻辑方法:

//Gson.class
public void toJson(Object src, Type typeOfSrc, JsonWriter writer) throws JsonIOException {
    //获取适配的 TypeAdapter
    TypeAdapter adapter = getAdapter(TypeToken.get(typeOfSrc));

    //下方代码均为储存并存入一些标准化的设置
    boolean oldLenient = writer.isLenient();
    writer.setLenient(true);
    boolean oldHtmlSafe = writer.isHtmlSafe();
    writer.setHtmlSafe(htmlSafe);
    boolean oldSerializeNulls = writer.getSerializeNulls();
    writer.setSerializeNulls(serializeNulls);

    //写入
    try {
        ((TypeAdapter) adapter).write(writer, src);
    } catch (IOException e) {
          throw new JsonIOException(e);
    } catch (AssertionError e) {
          throw new AssertionError("AssertionError (GSON " + GsonBuildConfig.VERSION + "): " + e.getMessage(), e);
    } finally {
        //还原
          writer.setLenient(oldLenient);
          writer.setHtmlSafe(oldHtmlSafe);
          writer.setSerializeNulls(oldSerializeNulls);
    }
}

基本的逻辑都在上面讲过了,不赘述。

到此为止 json 的序列化就基本完毕了。

四 总结

Gson 的代码封装很薄,本身不难,但是为了照顾兼容性,代码中存在很多条件判断,导致代码看上去很繁琐。同时为了兼顾性能做了很多有意思的设计,比如获取适配器的时候的双缓存设计,应该是为了提高解析器的复用效率,具体有待研究。

总结一下 Gson 的基本思路:

· 解析器(Gson)将使用者传入的字符串或对象存入读取器(Reader)或者写入器(Writer)中

· 解析器遍历并获取能够处理对应类型的适配器工厂(TypeAdapterFactory)

· 适配器工厂会创建出对应类型的适配器(TypeAdapter)

· 解析器将阅读器或写入器交给适配器

· 适配器自行通过业务逻辑操作读取器或写入器,输出需要的结果

· 解析器接收此输出,并交给使用者

五 一点唠叨

· Gson 太过强调功能的全面,解析器的初始化非常复杂

· JsonReader 的状态控制太过复杂和精密,笔者到现在也没全部弄清楚

· 在本篇源码解析中,Gson 内部还有一些拓展功能,比如 JsonElement、JsonParser 等的工具类没有提及

· 仅为个人的学习笔记,可能存在错误或者表述不清的地方,有缘补充

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/72959.html

相关文章

  • 追踪解析Gson源码(1)

    摘要:版本版本简介是谷歌开源的解析工具。其实几款产品的差别都很细微,有谷歌的信仰加成,所以在这里进行一次源码分析。至于和会在后续进行追踪。 零 前期准备 0 FBI WARNING 文章异常啰嗦且绕弯。 1 版本 Gson 版本 : gson 2.8.5 IDE : idea 2018.3 2 Gson 简介 Gson 是谷歌开源的 java json 解析工具。市场上同类的开源产品还有 F...

    sewerganger 评论0 收藏0
  • 追踪解析 ThreadPoolExecutor 源码

    摘要:的前位数用来表示线程的数量,后面三位用来表示线程池的状态。线程池的状态有五种,分别是,根据单词就能猜出大概。并且为了考虑性能问题,线程池的设计没有使用悲观锁关键字,而是大量使用了和机制。 零 前期准备 0 FBI WARNING 文章异常啰嗦且绕弯。 1 版本 JDK 版本 : OpenJDK 11.0.1 IDE : idea 2018.3 2 ThreadPoolExecutor ...

    gaomysion 评论0 收藏0
  • Retrofit源码分析

    摘要:看下图所示,摘自网络的创建流程源码分析实例是使用建造者模式通过类进行创建的。创建了一个含有对象实例的,并返回给源码分析添加一个调用适配器工厂,用于支持服务方法返回类型注意生产的是,那么又是什么呢可以看到源代码如下所示,它是一个接口。 目录介绍 1.首先回顾Retrofit简单使用方法 2.Retrofit的创建流程源码分析 2.1 Retrofit对象调用Builder()源码解...

    zero 评论0 收藏0
  • gson-plugin深入源码分析(三)

    摘要:六修改内部类的方法这个的方法是对类型的数据进行解析,我们判断输入的数据类型不是类型,就直接跳过解析,核心是在方法中插入方法。每一个类每一个内部类每一个匿名内部类,都会生成一个独立的文件,如。 一、项目地址 项目地址:github-gson-plugin 二、ReaderTools解析 /** * Created by tangfuling on 2018/10/23. */ pu...

    oujie 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<