輕觸開源(四)-Gson項目源碼解析_叄

ReflectiveTypeAdapterFactory完成Field屬性以後,將生成TypeAdapter返回。Gson經過Adapter來生成指定類型的對象。生成對象的過程,被ReflectiveTypeAdapterFactory.Adapter類記錄在本身的read方法中:java

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

Gson採用注入的方式往已生成的對象中注入屬性。在注入以前,會先調用ObjectConstructor來生成所須要的對象。這部分,非墨已經在以前的文章中表述過了。因爲ReflectiveTypeAdapterFactory.Adapter針對的是Gson對象的適配,所以在適配以前,會先調用JsonReader.beginObject來聲明處理入口。json

//CODE JsonReader.java
public void beginObject() throws IOException {
    int p = peeked;
    if (p == PEEKED_NONE) {
      p = doPeek();
    }
    if (p == PEEKED_BEGIN_OBJECT) {
      push(JsonScope.EMPTY_OBJECT);
      peeked = PEEKED_NONE;
    } else {
      throw new IllegalStateException("Expected BEGIN_OBJECT but was " + peek()
          + " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath());
    }
}
private void push(int newTop) {
    if (stackSize == stack.length) {
      int[] newStack = new int[stackSize * 2];
      int[] newPathIndices = new int[stackSize * 2];
      String[] newPathNames = new String[stackSize * 2];
      System.arraycopy(stack, 0, newStack, 0, stackSize);
      System.arraycopy(pathIndices, 0, newPathIndices, 0, stackSize);
      System.arraycopy(pathNames, 0, newPathNames, 0, stackSize);
      stack = newStack;
      pathIndices = newPathIndices;
      pathNames = newPathNames;
    }
    stack[stackSize++] = newTop;
  }

JsonReader調用beginObject方法,會調用push方法用於記錄一下當前操做的詞彙元素。這裏將記錄一個JsonScope.EMPTY_OBJECT的變量。咱們用如下Json串用於測試:緩存

String strJson = "{\"name\":david,age:19,room:{roomName:small,number:1}}";

這個Json串將被記錄在JsonReader的Buffer中。Gson在調用fromJson的時候,會調用一下JsonReader的peek操做,而peek操做,會調用內部的doPeek操做,doPeek操做會改變JsonReader中peeked變量的值和buffer偏移pos。peeked變量用於記錄下一個字符的屬性,pos變量用於記錄buffer緩存的偏移量。ide

此時,在Gson.fromJson中調用完reader的peek方法以後,JsonReader中pos索引的位置將指向' " '符號。測試

咱們回到ReflectiveTypeAdapterFactory的Adapter的read方法中去看:.net

@Override public T read(JsonReader in) throws IOException {
      ...
      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;
    }

Gson在調用完beginObject以後調用了JsonReader的hasNext方法,這個方法顧名思義,就是用來查看輸入源中是否還有待處理的字符。以後,若是此項爲真,那麼將調用JsonReader.nextName方法來獲取Json對象的屬性名字。code

public String nextName() throws IOException {
    int p = peeked;
    if (p == PEEKED_NONE) {
      p = doPeek();
    }
    String result;
    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()
          + " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath());
    }
    peeked = PEEKED_NONE;
    pathNames[stackSize - 1] = result;
    return result;
  }

nextName方法會先調用一個peek,查看下Buffer流的第一個字符是什麼屬性,而且只給三個屬性給出了不一樣的操做,分別是:對象

PEEKED_UNQUOTED_NAME  :對應 name:valueblog

PEEKED_SINGLE_QUOTED_NAME : 對應 'name':value索引

PEEKED_DOUBLE_QUOTED_NAME: 對應 "name":value

若是你但願Gson嚴格按照規範執行,也就是說你對Gson語法的寬容度爲false(調用JsonReader.setLenient(false))。那麼你所傳入的Json串,只要涉及到String類型的數據,都必須採用PEEKED_DOUBLE_QUOTED_NAME方式記錄。

在調用完不一樣類型的getName方法以後,取得第一個name值:"name"。以後將經過這個name來取得在對象field映射表boundFields中的BoundField值:

BoundField field = boundFields.get(name);
          if (field == null || !field.deserialized) {
            in.skipValue();
          } else {
            field.read(in, instance);
          }

若是你的Field已經標註爲不被反序列化,或者Json串中的name在你的對象中根本沒被標記,JsonReader將經過skipValue來過濾掉這些無用的信息。可是若是映射表中存在有這樣的Field,Adapter將調用BoundField的read方法來說讀取出來的值,注入到以前生成的instance對象中去。BoundField的read方法在ReflectiveTypeAdapterFactory中,以匿名類的方式來實現,

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...
    return new ReflectiveTypeAdapterFactory.BoundField(name, serialize, deserialize) {
      final TypeAdapter<?> typeAdapter = getFieldAdapter(context, field, fieldType);
      ....
      @Override void read(JsonReader reader, Object value)
          throws IOException, IllegalAccessException {
        Object fieldValue = typeAdapter.read(reader);
        if (fieldValue != null || !isPrimitive) {
          field.set(value, fieldValue);
        }
      }
       ....
    };
  }

  private TypeAdapter<?> getFieldAdapter(Gson gson, Field field, TypeToken<?> fieldType) {
    JsonAdapter annotation = field.getAnnotation(JsonAdapter.class);
    if (annotation != null) {
      TypeAdapter<?> adapter = getTypeAdapter(constructorConstructor, gson, fieldType, annotation);
      if (adapter != null) return adapter;
    }
    return gson.getAdapter(fieldType);
  }

BoundField會經過本身的TypeAdapter來read一個Value,而後經過調用set方法,往生成對象中注入。而內部的TypeAdapter的生成是經過getFieldAdapter方法來生成的,具體的內容,請參照非墨的上篇文章:

<輕觸開源(三)-Gson項目源碼解析_貳 http://www.javashuo.com/article/p-egkavmoj-ck.html>

相關文章
相關標籤/搜索