Gson源碼解析之-fromJson

上面我們學習了gson 的序列化過程方法 toJson 的源碼,相信對很多的流程有了一個瞭解,緊接着我們來學習下gson反序列化過程,fromJson .還是老樣子,代碼一點一點看。

我們先模擬一個反序列化過程

String json="{\"age\":30,\"name\":\"明\",\"len\":170]}";
TestMode jsTestMode=gson.fromJson(json,TestMode.class);
public class TestMode {
    @Expose(deserialize = true)
    private int age;

    @Expose(serialize = false, deserialize = true)
    String name;
    @Expose(deserialize = true)
    @SerializedName("len")
    int length;

//    public List<TestMode> getTestMode() {
//        return testMode;
//    }
//
//    public void setTestMode(List<TestMode> testMode) {
//        this.testMode = testMode;
//    }
//
//    List<TestMode> testMode;
    public TestMode(){
    }

    public TestMode(int age, String name, int length) {
        this.age = age;
        this.name = name;
        this.length = length;
    }

    public int getLength() {
        return length;
    }

    public void setLength(int length) {
        this.length = length;
    }



    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "TestMode{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", length=" + length +
//                ", testMode=" + testMode +
                '}';
    }
}
//classofT 就 是我們要將json 字符串反序列位的對象的.class 類
 public <T> T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException {
      //生成一個object對象 ,class 轉爲type接口類型,因爲class<T> 本身實現了type接口
  Object object = fromJson(json, (Type) classOfT);
      //將object 轉爲 具體的類對象並返回
    return Primitives.wrap(classOfT).cast(object);
  }
  //
public <T> T fromJson(String json, Type typeOfT) throws JsonSyntaxException {
    if (json == null) {
      return null;
    }
    // 將json 字符串封裝到StringReader 類中 StringReader繼承自Reader 類 用來處理流相關字符串。
    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 也是反序列的關鍵類,基本所有的字符到對象的具體的操作邏輯都是由它來實現的
    JsonReader jsonReader = newJsonReader(json);
    T object = (T) fromJson(jsonReader, typeOfT);
    //在整個反序列化過程結束之前效驗 jsonReader 的 peeked 的狀態
    //如果 peeker 未處於結束狀態,則會報錯
    assertFullConsumption(object, jsonReader);
    return object;
  }

前面是一些準備的fromJson 構造函數,下面看主要部分

public <T> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
    boolean isEmpty = true;
   // 接受不符合規定的json變量的值
    boolean oldLenient = reader.isLenient();
    //強制設置爲接受
    reader.setLenient(true);
    try {
//此處相當於調用了一次 JsonReader 中的 doPeek() 方法,返回下一個令牌的類型而不消耗它,設置當前令牌
      reader.peek();
      isEmpty = false;
        //TypeToken 本質上是 Class 的增強封裝類
      TypeToken<T> typeToken = (TypeToken<T>) TypeToken.get(typeOfT);
      //根據要轉化的實體類型,獲取相應的適配器
      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);
    } catch (AssertionError e) {
      AssertionError error = new AssertionError("AssertionError (GSON " + GsonBuildConfig.VERSION + "): " + e.getMessage());
      error.initCause(e);
      throw error;
    } finally {
      reader.setLenient(oldLenient);
    }
  }

主要看下 getAdapter 方法

public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
    //TypeToken<T> 類字面翻譯是類型令牌,其實就是保存了這個類的屬性,類型和hashcode等值爲後期操作準備
    //typeTokenCache 內部是一個線程安全的ConcurrentHashMap ,它主要用來緩存類型令牌,如果能夠獲取到值,那說明之前已經有了相同的類型令牌,也就是說是同一個,如果有了就直接返回
    TypeAdapter<?> cached = typeTokenCache.get(type == null ? NULL_KEY_SURROGATE : type);
    if (cached != null) {
      return (TypeAdapter<T>) cached;
    }
   //calls 是一個 ThreadLocal 對象 ,當前線程中保存一份緩存,裏面存入的對象會在 finally 代碼塊中清空掉
    Map<TypeToken<?>, FutureTypeAdapter<?>> threadCalls = calls.get();
    boolean requiresThreadLocalCleanup = false;
    if (threadCalls == null) {
      threadCalls = new HashMap<TypeToken<?>, FutureTypeAdapter<?>>();
      calls.set(threadCalls);
      requiresThreadLocalCleanup = true;
    }
 
    // the key and value type parameters always agree
    //鍵和值類型參數始終一致 
    FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type);
    if (ongoingCall != null) {
      return ongoingCall;
    }
 
    try {
      FutureTypeAdapter<T> call = new FutureTypeAdapter<T>();
      threadCalls.put(type, call);
  //factories 是適配器集合工廠,通過遍歷找到相關類型
      for (TypeAdapterFactory factory : factories) {
   //根據上邊我們的實體類 type可以判斷最終執行 ReflectiveTypeAdapterFactory 的create方法返回值不爲空,所以他的適配器類型是這樣確定的 ,如果不算自定義是41種適配器,當然,方法對於不是對應類型的參數會返回 null,所以不爲空說明找到了對應的適配器類型。
   //完整的適配器包括它類本身的適配器類型,還包括它所有變量的適配器類型,call存儲的就是這樣的數據,因爲create 執行後,會通過反射獲取到所有類中變量名稱,並且通過getAdapter 也就是當前方法獲取類型,這是如果之前已經有這個適配器存儲了,就直接返回了ongoingCall
        TypeAdapter<T> candidate = factory.create(this, type);
        if (candidate != null) {
         // 將對應的適配器類型緩存起來
          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();
      }
    }
  }

這裏返回了該類對應的適配器類型。並且對應變量也會調用到這個方法來獲取變量的適配器類型。

typeAdapter.read(reader); 是適配器中的read 方法,不同的類對應的適配器是不同的

所有的適配器類都實現了TypeAdapterFactory 適配器工廠接口, 重寫了create 方法,而create 的返回值是一個adapter類,所有的adapter  都繼承 TypeAdapter<T>  並且實現了其中的抽象方法read 和write。我們的TestMode 對應的是 ReflectiveTypeAdapterFactory
factories.add(TypeAdapters.INET_ADDRESS_FACTORY);  這個是基本類型等的適配器 是TypeAdapters ,例如bool string 等

直接看ReflectiveTypeAdapterFactory的create

@Override public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) {
    Class<? super T> raw = type.getRawType();
    //這裏用於比對類型,如果不是相應的類型就返回null
    //確定此* {@code Class}對象表示的類或接口是否與指定的{{code code}}參數所表示的類或接口相同,或者是該類或接口的超類或父接口。 。如果是,則返回{@code true}; *否則返回{@code false}
    //很顯然,這裏返回的是true 應爲我們的類是TestMode 是一個class類
    if (!Object.class.isAssignableFrom(raw)) {
      return null; // it's a primitive!
    }
    //通用對象構造工廠
    ObjectConstructor<T> constructor = constructorConstructor.get(type);
    return new Adapter<T>(constructor, getBoundFields(gson, type, raw));
  }

然後看下adapter 構造方法

getBoundFields 方法就是通過反射獲取所有變量屬性
Map<String, BoundField> result = new LinkedHashMap<String, BoundField>();
key 對應的是字段名,BoundField 是對該字段的屬性的保存。
static abstract class BoundField {
    final String name;
    final boolean serialized;
    final boolean deserialized;

    protected BoundField(String name, boolean serialized, boolean deserialized) {
      this.name = name;
      this.serialized = serialized;
      this.deserialized = deserialized;
    }
    abstract boolean writeField(Object value) throws IOException, IllegalAccessException;
    abstract void write(JsonWriter writer, Object value) throws IOException, IllegalAccessException;
    abstract void read(JsonReader reader, Object value) throws IOException, IllegalAccessException;
  }
現在回到typeAdapter.read 方法 while 循環執行,直到反序列化結束。
 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;
      }
      //創建一個實例化對象 就是 TestMode
     
      T instance = constructor.construct();

      try {
        //開始反序列化前的準備
        in.beginObject();
       //是否還有下一個,沒有返回false 有返回true 並設置指令
        while (in.hasNext()) {
          //獲取json 中的一個key
          String name = in.nextName();
         //通過key 找到對應的屬性對象
          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 {...}
}

我們之前做的所有的準備工作都會在這個類中提現出來。字符傳中提取key 並獲取到field ,然後執行field 的read 方法,BoundField 重寫read 方法

 

 @Override void read(JsonReader reader, Object value)
          throws IOException, IllegalAccessException {
       //根據json字符串和適配器,讀取當前field 的value 值
        Object fieldValue = typeAdapter.read(reader);
        if (fieldValue != null || !isPrimitive) {
         //根據field  (key 對應的field)設置值到value (TestDoem) 中 fieldValue (對象值)
          field.set(value, fieldValue);
        }
      }

到這裏整個流程就結束了,下面我們來看前面的幾個具體操作類

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
}

beginObject()

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()

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;
}

到此反序列化源碼學習完成了。

參考:

https://segmentfault.com/a/1190000017868423?utm_source=tag-newest

https://www.jianshu.com/p/da21b3a59b47

   

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章