Gson源碼解析和它的設計模式

前言

以前一段時間,準備把糗百的項目中json解析的模塊中的原生Json解析換成gson解析,工做比較繁雜,坑多,所以爲了防止出錯,我還對Gson作了一個源碼分析。這一篇就是Gson源碼分析的總結,同時對Gson內部運用的設計模式也進行了總結,相信瞭解了它的源碼和運行機制,對於使用Gson的使用會更有幫助。html

Gson簡介

Gson,就是幫助咱們完成序列化和反序列化的工做的一個庫。json

  • 平常用法
UserInfo userInfo = getUserInfo();
        Gson gson = new Gson();
        String jsonStr = gson.toJson(userInfo); // 序列化
        UserInfo user = gson.fromJson(jsonStr,UserInfo.class);  // 反序列化
        
複製代碼

實際上咱們用的最多的是Gson的反序列化,主要在解析服務器返回的json串。所以,後面的文章也會以Gson中的反序列化的過程爲主來分析代碼。設計模式

在分析以前,咱們先作個簡單的猜測,要如何實現反序列化的流程的,Gson大致會作一下這三件事:緩存

  • 反射建立該類型的對象
  • 把json中對應的值賦給對象對應的屬性
  • 返回該對象。

事實上,Gson想要把json數據反序列化基本都逃不掉這三個步驟,可是這三個步驟就像小品裏分三步把大象裝進冰箱同樣。咱們知道最複雜的一步就是把大象裝進去,畢竟,開冰箱門或者關冰箱門你們都會的嘛。在Gson中,複雜的就是怎樣把json中對應數據放入對應的屬性中。而這個問題的答案就是Gson的TypeAdapter。bash

Gson核心:TypeAdapter

TypeAdapter是Gson的核心,它的意思是類型適配器,而說到適配器,你們都會想到適配器模式,沒錯,這個TypeAdapter的設計這確實是一個適配器模式,由於Json數據接口和Type的接口二者是沒法兼容,所以TypeAdapter就是來實現兼容,把json數據讀到Type中,把Type中的數據寫入到Json裏。服務器

public abstract class TypeAdapter<T> {
 // JsonWriter表明Json數據,T則是對應的Type的對象
  public abstract void write(JsonWriter out, T value) throws IOException;
 // JsonWriter表明Json數據,T則是對應的Type的對象
  public abstract T read(JsonReader in) throws IOException;
  ...
  ...
  ...
}

複製代碼

簡單而言,TypeAdapter的做用就是針對Type進行適配,保證把json數據讀到Type中,或者把Type中的數據寫入到Json裏數據結構

Type和TypeAdapter的對應關係

Gson會爲每一種類型建立一個TypeAdapter,一樣的,每個Type都對應惟一一個TypeAdapter多線程

而全部Type(類型),在Gson中又能夠分爲基本類型和複合類型(非基本類型)app

  • 基本類型(Integer,String,Uri,Url,Calendar...):這裏的基本類型不只包括Java的基本數據類型,還有不少其餘的數據類型
  • 複合類型(非基本類型):即除了基本類型以外的類型,每每是咱們自定義的一些業務相關的JavaBean,好比User,Article.....等等。

這裏的基本類型和複合類型(非基本類型)是筆者定義的詞彙,由於這樣定義對於讀者理解Gson源碼和運行機制更有幫助。ide

如上圖,每一種基本類型都會建立一個TypeAdapter來適配它們,而全部的複合類型(即咱們本身定義的各類JavaBean)都會由ReflectiveTypeAdapter來完成適配

TypeAdapter和Gson運行機制

既然講到了每種Type都有對應的TypeAdapter,那麼爲何說TypeAdapter是Gson的核心呢?咱們能夠看看Gson究竟是如何實現Json解析的呢,下圖是Gson完成json解析的抽象簡化的流程圖:

如上圖,若是是基本類型,那麼對應的TypeAdapter就能夠直接讀寫Json串,若是是複合類型,ReflectiveTypeAdapter會反射建立該類型的對象,並逐個分析其內部的屬性的類型,而後重複上述工做。直至全部的屬性都是Gson認定的基本類型並完成讀寫工做。

TypeAdapter源碼分析

當類型是複合類型的時候,Gson會建立ReflectiveTypeAdapter,咱們能夠看看這個Adapter的源碼:

// 建立ReflectiveTypeAdapter
new Adapter<T>(constructor, getBoundFields(gson, type, raw));

...
...

/**
* ReflectiveTypeAdapter是ReflectiveTypeAdapterFactory的內部類,其實際的類名就是Adapter
* 本文只是爲了區別其餘的TypeAdapter而叫它 ReflectiveTypeAdapter
**/
public static final class Adapter<T> extends TypeAdapter<T> {
    // 該複合類型的構造器,用於反射建立對象
    private final ObjectConstructor<T> constructor;
    // 該類型內部的全部的Filed屬性,都經過map存儲起來
    private final Map<String, BoundField> boundFields;

    Adapter(ObjectConstructor<T> constructor, Map<String, BoundField> boundFields) {
      this.constructor = constructor;
      this.boundFields = boundFields;
    }

 //JsonReader是Gson封裝的對Json相關的操做類,能夠依次讀取json數據
 // 相似的能夠參考Android封裝的對XML數據解析的操做類XmlPullParser
    @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(); //開始逐個讀取json串中的key
          BoundField field = boundFields.get(name); // 經過key尋找對應的屬性
          if (field == null || !field.deserialized) {
            in.skipValue();
          } else {
            field.read(in, instance); // 將json串的讀取委託給了各個屬性
          }
        }
      } catch (IllegalStateException e) {
        throw new JsonSyntaxException(e);
      } catch (IllegalAccessException e) {
        throw new AssertionError(e);
      }
      in.endObject(); // 到對應的「}」結束
      return instance;
    }
    ...
    ...
  }
  
複製代碼

Gson內部並無ReflectiveTypeAdapter這個類,它其其實是ReflectiveTypeAdapterFactory類一個名叫Adapter的內部類,叫它ReflectiveTypeAdapter是爲了表意明確。

咱們看到,ReflectiveTypeAdapter內部會首先建立該類型的對象,而後遍歷該對象內部的全部屬性,接着把json傳的讀去委託給了各個屬性。

被委託的BoundField內部又是如何作的呢?BoundField這個類,是對Filed相關操做的封裝,咱們來看看BoundField是如何建立的,以及內部的工做原理。

// 建立ReflectiveTypeAdapter getBoundFields獲取該類型全部的屬性
new Adapter<T>(constructor, getBoundFields(gson, type, raw));

...
...


private Map<String, BoundField> getBoundFields(Gson context, TypeToken<?> type, Class<?> raw) {
    // 建立一個Map結構,存放全部的BoundField
    Map<String, BoundField> result = new LinkedHashMap<String, BoundField>();
    if (raw.isInterface()) {
      return result;
    }

    Type declaredType = type.getType();
    while (raw != Object.class) { // 若是類型是Object則結束循環
      Field[] fields = raw.getDeclaredFields(); // 獲取該類型的全部的內部屬性
      for (Field field : fields) {
        boolean serialize = excludeField(field, true);
        boolean deserialize = excludeField(field, false);
        if (!serialize && !deserialize) {
          continue;
        }
        accessor.makeAccessible(field);
        Type fieldType = $Gson$Types.resolve(type.getType(), raw, field.getGenericType());
        List<String> fieldNames = getFieldNames(field); // 獲取該Filed的名字(Gson經過註解能夠給一個屬性多個解析名)
        BoundField previous = null;
        for (int i = 0, size = fieldNames.size(); i < size; ++i) {
          String name = fieldNames.get(i);
          // 多個解析名,第一做爲默認的序列化名稱
          if (i != 0) serialize = false; // only serialize the default name
          // 建立BoundField
          BoundField boundField = createBoundField(context, field, name,
              TypeToken.get(fieldType), serialize, deserialize);
        // 將BoundField放入Map中,獲取被替換掉的value(若是有的話)
          BoundField replaced = result.put(name, boundField);
          // 作好記錄
          if (previous == null) previous = replaced;
        }
        if (previous != null) {
        // 若是previous != null證實出現了兩個相同的Filed name,直接拋出錯誤
        // 注:Gson不容許定義兩個相同的名稱的屬性(父類和子類之間可能出現)
          throw new IllegalArgumentException(declaredType
              + " declares multiple JSON fields named " + previous.name);
        }
      }
      type = TypeToken.get($Gson$Types.resolve(type.getType(), raw, raw.getGenericSuperclass()));
      raw = type.getRawType(); // 獲取父類類型,最終會索引到Object.由於Object是全部對象的父類
    }
    return result;
  }


複製代碼

上面這段代碼的主要工做就是,找到該類型內部的全部屬性,並嘗試逐一封裝成BoundField。

// 根據每一個Filed建立BoundField(封裝Filed讀寫操做)
  private ReflectiveTypeAdapterFactory.BoundField createBoundField(
      final Gson context, final Field field, final String name,
      final TypeToken<?> fieldType, boolean serialize, boolean deserialize) {
      // 是不是原始數據類型 (int,boolean,float...)
    final boolean isPrimitive = Primitives.isPrimitive(fieldType.getRawType());
    ...
    ...
    if (mapped == null){
        // Gson嘗試獲取該類型的TypeAdapter,這個方法咱們後面也會繼續提到。
        mapped = context.getAdapter(fieldType);
    }
    // final變量,便於內部類使用
    final TypeAdapter<?> typeAdapter = mapped;
    return new ReflectiveTypeAdapterFactory.BoundField(name, serialize, deserialize) {
      ...
      ...
      // ReflectiveTypeAdapter委託的Json讀操做會調用到這裏
      @Override void read(JsonReader reader, Object value)
          throws IOException, IllegalAccessException {
          // 經過該屬性的類型對應的TypeAdapter嘗試讀取json串
          //若是是基礎類型,則直接讀取,
          //若是是複合類型則遞歸以前的流程
        Object fieldValue = typeAdapter.read(reader);
        if (fieldValue != null || !isPrimitive) {
          field.set(value, fieldValue); //更新filed值 
        }
      }
      @Override public boolean writeField(Object value) throws IOException, IllegalAccessException {
        if (!serialized) return false;
        Object fieldValue = field.get(value);
        return fieldValue != value; // avoid recursion for example for Throwable.cause
      }
    };
  }
    
    
複製代碼

假設該複合類型中全部的屬性的類型是String,則屬性所對應的TypeAdapter以及其讀寫方式以下:

public static final TypeAdapter<String> STRING = new TypeAdapter<String>() {
    @Override
    public String read(JsonReader in) throws IOException {
      JsonToken peek = in.peek();   // 獲取下一個jsontoken而不消耗它
      if (peek == JsonToken.NULL) {
        in.nextNull();
        return null;
      }
      /* coerce booleans to strings for backwards compatibility */
      if (peek == JsonToken.BOOLEAN) {
        return Boolean.toString(in.nextBoolean()); // 若是時布爾值,則轉化爲String
      }
      return in.nextString();   // 從json串中獲取這個String類型的value並消耗它
    }
    @Override
    public void write(JsonWriter out, String value) throws IOException {
      out.value(value); // 不作任何處理直接寫入Json串
    }
  }
  
複製代碼

到這裏,關於Gson的TypeAdapter的原理也就講得差很少了,回顧一下,由於Type有兩類,對應的TypeAdapter也有兩類,一類是ReflectiveTypeAdapter,針對複合類型,它的做用是把複合類型拆解成基本類型,另外一類是針對基本類型的TypeAdapter,實現對應基本類型的Json串讀寫工做。而Gson本質上就是按照這兩類TypeAdapter來完成Json解析的。

能夠說,到這裏,咱們如今對Gson的基本工做流程有了一個基本的認識。

再一次分析Gson的執行邏輯

事實上,文章到這裏結合上面的源碼剖析和簡化流程圖,咱們已經能夠比較比較真實的分析出Gson的執行邏輯了。

Gson反序列化的平常用法:

UserInfo userInfo = getUserInfo();
        Gson gson = new Gson();
        String jsonStr = getJsonData();
        UserInfo user = gson.fromJson(jsonStr,UserInfo.class);  // 反序列化
        
複製代碼

gson.fromJson(jsonStr,UserInfo.class)方法內部真實的代碼執行流程大體以下:

  • 對jsonStr,UserInfo.class這兩個數據進行封裝
  • 經過UserInfo.class這個Type來獲取它對應的TypeAdapter
  • 拿到對應的TypeAdapter(ReflectiveTypeAdapterFactor),並執行讀取json的操做
  • 返回UserInfo這個類型的對象。

咱們描述的這個流程和Gson代碼真實的執行流程已經沒太大的區別了。

TypeAdapter的建立與工廠模式

Gson中除了適配器模式以外最重要的設計模式,可能就是工廠模式吧。由於Gson中衆多的TypeAdapter都是經過工廠模式統一建立的:

public interface TypeAdapterFactory {
    // 建立TypeAdapter的接口
  <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type);
}


複製代碼

咱們能夠看看ReflectiveTypeAdapterFactory的實現

// ReflectiveTypeAdapterFactory的實現
public final class ReflectiveTypeAdapterFactory implements TypeAdapterFactory {

  @Override public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) {
    Class<? super T> raw = type.getRawType();
    // 只要是Object的子類,就能匹配上
    if (!Object.class.isAssignableFrom(raw)) {
     // it's a primitive! return null; } ObjectConstructor<T> constructor = constructorConstructor.get(type); return new Adapter<T>(constructor, getBoundFields(gson, type, raw)); } } 複製代碼

Gson在其構造方法中,就提早把全部的TypeAdapterFactory放在緩存列表中。

Gson(final Excluder excluder, final FieldNamingStrategy fieldNamingStrategy,
      final Map<Type, InstanceCreator<?>> instanceCreators, boolean serializeNulls,
      boolean complexMapKeySerialization, boolean generateNonExecutableGson, boolean htmlSafe,
      boolean prettyPrinting, boolean lenient, boolean serializeSpecialFloatingPointValues,
      LongSerializationPolicy longSerializationPolicy, String datePattern, int dateStyle,
      int timeStyle, List<TypeAdapterFactory> builderFactories,
      List<TypeAdapterFactory> builderHierarchyFactories,
      List<TypeAdapterFactory> factoriesToBeAdded) {
    ...
    ...
    ...

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

    // users type adapters
    factories.addAll(factoriesToBeAdded);

    // type adapters for basic platform types
    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);
    TypeAdapter<Number> longAdapter = longAdapter(longSerializationPolicy);
    factories.add(TypeAdapters.newFactory(long.class, Long.class, longAdapter));
    factories.add(TypeAdapters.newFactory(double.class, Double.class,
            doubleAdapter(serializeSpecialFloatingPointValues)));
    factories.add(TypeAdapters.newFactory(float.class, Float.class,
            floatAdapter(serializeSpecialFloatingPointValues)));
    factories.add(TypeAdapters.NUMBER_FACTORY);
    factories.add(TypeAdapters.ATOMIC_INTEGER_FACTORY);
    factories.add(TypeAdapters.ATOMIC_BOOLEAN_FACTORY);
    factories.add(TypeAdapters.newFactory(AtomicLong.class, atomicLongAdapter(longAdapter)));
    factories.add(TypeAdapters.newFactory(AtomicLongArray.class, atomicLongArrayAdapter(longAdapter)));
    factories.add(TypeAdapters.ATOMIC_INTEGER_ARRAY_FACTORY);
    factories.add(TypeAdapters.CHARACTER_FACTORY);
    factories.add(TypeAdapters.STRING_BUILDER_FACTORY);
    factories.add(TypeAdapters.STRING_BUFFER_FACTORY);
    factories.add(TypeAdapters.newFactory(BigDecimal.class, TypeAdapters.BIG_DECIMAL));
    factories.add(TypeAdapters.newFactory(BigInteger.class, TypeAdapters.BIG_INTEGER));
    factories.add(TypeAdapters.URL_FACTORY);
    factories.add(TypeAdapters.URI_FACTORY);
    factories.add(TypeAdapters.UUID_FACTORY);
    factories.add(TypeAdapters.CURRENCY_FACTORY);
    factories.add(TypeAdapters.LOCALE_FACTORY);
    factories.add(TypeAdapters.INET_ADDRESS_FACTORY);
    factories.add(TypeAdapters.BIT_SET_FACTORY);
    factories.add(DateTypeAdapter.FACTORY);
    factories.add(TypeAdapters.CALENDAR_FACTORY);
    factories.add(TimeTypeAdapter.FACTORY);
    factories.add(SqlDateTypeAdapter.FACTORY);
    factories.add(TypeAdapters.TIMESTAMP_FACTORY);
    factories.add(ArrayTypeAdapter.FACTORY);
    factories.add(TypeAdapters.CLASS_FACTORY);

    // type adapters for composite and user-defined types
    factories.add(new CollectionTypeAdapterFactory(constructorConstructor));
    factories.add(new MapTypeAdapterFactory(constructorConstructor, complexMapKeySerialization));
    this.jsonAdapterFactory = new JsonAdapterAnnotationTypeAdapterFactory(constructorConstructor);
    factories.add(jsonAdapterFactory);
    factories.add(TypeAdapters.ENUM_FACTORY);
    // 注意,ReflectiveTypeAdapterFactor是要最後添加的
    factories.add(new ReflectiveTypeAdapterFactory(
        constructorConstructor, fieldNamingStrategy, excluder, jsonAdapterFactory));

    this.factories = Collections.unmodifiableList(factories);
  }
  
複製代碼

這裏咱們可以看到,ReflectiveTypeAdapterFactor最後被添加進去的,由於這裏的添加順序是有講究的。咱們看看getAdapter(type)方法就能知道。

getAdapter(type)這個方法就是gson經過type尋找到對應的TypeAdapter,這是Gson中很是重要的一個方法。

// 經過Type獲取TypeAdapter
public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {

    try {
      
      // 遍歷緩存中全部的TypeAdapterFactory,
      for (TypeAdapterFactory factory : factories) {
      //若是類型匹配,則create()將會返回一個TypeAdapter,不然爲nulll
        TypeAdapter<T> candidate = factory.create(this, type);
        if (candidate != null) {
            // candidate不爲null,證實找到類型匹配的TypeAdapter.
          return candidate;
        }
      }
      throw new IllegalArgumentException("GSON (" + GsonBuildConfig.VERSION + ") cannot handle " + type);
    }
  }
  
複製代碼

ReflectiveTypeAdapterFactory之因此在緩存列表的最後一個,就是由於它能匹配幾乎任何類型,所以,咱們爲一個類型遍歷時,只能先判斷它是否是基本類型,若是都不成功,最後再使用ReflectiveTypeAdapterFactor進行判斷。

這就是Gson中用到的工廠模式。

關於代碼的難點

咱們從新回到getAdapter(type)這個方法,這個方法裏面有一些比較難理解的代碼

// 經過Type獲取TypeAdapter
public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
    // typeTokenCache是Gson的一個Map類型的緩存結構
    // 0,首先嚐試從緩存中獲取是否有對應的TypeAdapter
    TypeAdapter<?> cached = typeTokenCache.get(type == null ? NULL_KEY_SURROGATE : type);
    if (cached != null) {
      return (TypeAdapter<T>) cached;
    }

    // 1,alls 是Gson內部的ThreadLocal變量,用於保存一個Map對象
    // map對象也緩存了一種FutureTypeAdapter
    Map<TypeToken<?>, FutureTypeAdapter<?>> threadCalls = calls.get();
    boolean requiresThreadLocalCleanup = false;
    if (threadCalls == null) {
      threadCalls = new HashMap<TypeToken<?>, FutureTypeAdapter<?>>();
      calls.set(threadCalls);
      requiresThreadLocalCleanup = true;
    }

    //2,若是從ThreadLocal內部的Map中找到緩存,則直接返回
    // the key and value type parameters always agree
    FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type);
    if (ongoingCall != null) {
      return ongoingCall;
    }

    try {
    建立一個FutureTypeAdapter
      FutureTypeAdapter<T> call = new FutureTypeAdapter<T>();
      // 緩存
      threadCalls.put(type, call);

      for (TypeAdapterFactory factory : factories) {
      // 遍歷全部的TypeAdapterFactory
        TypeAdapter<T> candidate = factory.create(this, type);
        if (candidate != null) {
        // 3, 設置委託的TypeAdapter
          call.setDelegate(candidate);
          // 緩存到Gson內部的Map中,
          typeTokenCache.put(type, candidate);
          return candidate;
        }
      }
      //若是遍歷都沒有找到對應的TypeAdapter,直接拋出異常
      throw new IllegalArgumentException("GSON (" + GsonBuildConfig.VERSION + ") cannot handle " + type);
    } finally {
    // 4,移除threadCalls內部緩存的 FutureTypeAdapter
      threadCalls.remove(type);

      if (requiresThreadLocalCleanup) {
      //ThreadLocal移除該線程環境中的Map
        calls.remove();
      }
    }
  }
複製代碼

上述代碼比較難以理解的地方我標註了序號,用於後面解釋代碼

方法裏出現了FutureTypeAdapter這個TypeAdapter,彷佛很奇怪,由於它沒有FutureTypeAdapterFactory這個工廠類,咱們先來看看 FutureTypeAdapter的內部構造

static class FutureTypeAdapter<T> extends TypeAdapter<T> {
    private TypeAdapter<T> delegate;

    public void setDelegate(TypeAdapter<T> typeAdapter) {
      if (delegate != null) {
        throw new AssertionError();
      }
      delegate = typeAdapter;
    }

    @Override public T read(JsonReader in) throws IOException {
      if (delegate == null) {
        throw new IllegalStateException();
      }
      return delegate.read(in);
    }

    @Override public void write(JsonWriter out, T value) throws IOException {
      if (delegate == null) {
        throw new IllegalStateException();
      }
      delegate.write(out, value);
    }
  }
  
  
複製代碼

這是一個明顯的委派模式(也可稱爲代理模式)的包裝類。咱們都知道委託模式的功能是:隱藏代碼具體實現,經過組合的方式一樣的功能,避開繼承帶來的問題。可是在這裏使用委派模式彷佛並非基於這些考慮。而是爲了不陷入無限遞歸致使對棧溢出的崩潰。

爲何這麼說呢?咱們來舉個例子:

// 定義一個帖子的實體
public class Article {
    // 表示帖子中連接到其餘的帖子
    public Article linkedArticle;
    .....
    .....
    .....
    
    
}

複製代碼

Article類型中有一個linkedArticle屬性,它的類型仍是Article,根據咱們以前總結的簡化流程圖:

你會發現這裏有一個死循環,或者說沒法終結的遞歸。爲了不這個問題,因此先建立一個代理類,等到遞歸遇到一樣的類型時直接複用返回,避免無限遞歸。也就是註釋2那段代碼的用意,在註釋3處,再將建立成功的TypeAdapter設置到代理類中。就基本解決這個問題了。

固然說基本解決,是由於還要考慮多線程的環境,因此就出現了ThreadLocal這個線程局部變量,這保證了它只會在單個線程中緩存,並且會在單次Json解析完成後移出緩存。見上文註釋1和註釋4。這是由於無限遞歸只會發生在單次Json解析中,並且Gson內部已經有了一個TypeAdapterde 全局緩存(typeTokenCache),見註釋0.

潛在的遞歸循環: gson.getAdapter(type) ---> (ReflectiveTypeAdapterFactory)factory.create(this, type) ---> getBoundFields() ---> createBoundField() ---> (Gson)context.getAdapter(fieldType)

關於Gson自定義解析

上文只講到了Gson本身內部是如何實現Json解析的,其實Gson也提供了一些自定義解析的接口。主要是兩種:

  • 本身實現繼承TypeAdapter
  • 實現JsonSerializer/JsonDeserializer接口

那麼,二者有什麼區別呢?

追求效率更高,選第一種,想要操做更簡單,實現更靈活,選第二種。

爲何這麼說?舉個例子,假設咱們須要爲Article這個JavaBean自定義解析,若是咱們選擇繼承TypeAdapter的話,須要先實現TypeAdapter,而後註冊。

// 繼承TypeAdapter,實現抽象方法
    public class ArticleTypeAdapter extends TypeAdapter<Article>{

        @Override
        public void write(JsonWriter out, Article value) throws IOException {
            // 實現把Article中的實體數據的寫入到JsonWriter中,實現序列化
        }

        @Override
        public Article read(JsonReader in) throws IOException {
            // 須要建立Article對象
            // 把 JsonReader中的json串讀出來,並設置到Article對象中
            return null;
        }
    }
    
    ...
    ...
    // 註冊
    Gson mGson = new GsonBuilder()
    .registerTypeAdapter(Article.class, new ArticleTypeAdapter<>())//實際上註冊到Gson的factories列表中
    .create();
    
    
複製代碼

這樣就實現了自定義的Json解析,這種方式的讀寫效率很高,可是不太靈活,由於必需要同時實現序列化和反序列化的工做。

而實現JsonSerializer/JsonDeserializer接口這種方式相對更簡單

//JsonSerializer(json序列話)/JsonDeserializer(反序列化)可按需實現
    public class ArticleTypeAdapter implements JsonDeserializer<Article> {
        @Override
        public Article deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
             // 須要建立Article對象
            // 並從JsonElement中把封裝好的Json數據結構讀出來,並設置到Article對象中
            return null;
        }
    }


    // 註冊
    Gson mGson = new GsonBuilder()
    .registerTypeAdapter(Article.class, new ArticleTypeAdapter<>())//實際上註冊到Gson的factories列表中
    .create();
    
複製代碼

咱們能夠看到,二者的區別,是後者更加靈活,序列化/返序列化可按需選擇,並且它使用了JsonElement對Json數據進行再封裝,從而使咱們操做Json數據更加簡單。不過正是由於使用了 JsonElement這種對Json數據再封裝的類,而不是更加原始的JsonReader致使了代碼執行效率的下降。

如上圖所示,本質上就是多了一箇中間層,致使解析效率的下降。不過話說回來,只要不是很是大批量複雜結構的連續解析,這種效率差別咱們能夠忽略不計,所以平常的開發,你們經過JsonSerializer/JsonDeserializer接口來實現自定義解析是一個相對更好的選擇。

相關文章
相關標籤/搜索