Gson源码分析

Gson在Android开发中,我们经常用到,主要用于把服务端给我们返回的json字符串,解析成相应的实体类,我们今天来看一下源码。

image.png

Gson通常是创建一个实例,然后调用toJson和fromJson方法使用。Gson实例是线程安全的,你可以在多线程中重用它
如果你只需要默认的配置,你可以通过调用new Gson()来创建一个默认的实例。你也可以自定义配置,通过调用GsonBuilder来创建Gson实例。


image.png
  Gson gson = new Gson();
        Type listType = new TypeToken>(){}.getType();
        List target = new LinkedList<>();
        target.add("blah");
        String json = gson.toJson(target,listType); //序列化
        List target2 = gson.fromJson(json,listType); //反序列化

关于TypeToken的问题

Type listType = new TypeToken>(){}.getType();
创建TypeToken对象后面加了大括号,表示我们创建了一个匿名内部类。我们点进去TypeToken源码进去看一下


image.png

我们看这个构造器的修饰符是protected,不是public

/**
   * Converts a tree of {@link JsonElement}s into its equivalent JSON representation.
   *
   * @param jsonElement root of a tree of {@link JsonElement}s
   * @return JSON String representation of the tree
   * @since 1.4
   */
  public String toJson(JsonElement jsonElement) {
    StringWriter writer = new StringWriter();
    toJson(jsonElement, writer);
    return writer.toString();
  }

  /**
   * Writes out the equivalent JSON for a tree of {@link JsonElement}s.
   *
   * @param jsonElement root of a tree of {@link JsonElement}s
   * @param writer Writer to which the Json representation needs to be written
   * @throws JsonIOException if there was a problem writing to the writer
   * @since 1.4
   */
  public void toJson(JsonElement jsonElement, Appendable writer) throws JsonIOException {
    try {
      JsonWriter jsonWriter = newJsonWriter(Streams.writerForAppendable(writer));
      toJson(jsonElement, jsonWriter);
    } catch (IOException e) {
      throw new JsonIOException(e);
    }
  }

这个方法是把实体序列化,转化为json字符串


image.png

TypeAdapter adapter = getAdapter(TypeToken.get(typeOfSrc)); //获取类型的TypeAdapter

 /**
   * Returns the type adapter for {@code} type.
   *
   * @throws IllegalArgumentException if this GSON cannot serialize and
   *     deserialize {@code type}.
   */
  @SuppressWarnings("unchecked")
  public  TypeAdapter getAdapter(TypeToken type) {
    TypeAdapter cached = typeTokenCache.get(type == null ? NULL_KEY_SURROGATE : type);
    if (cached != null) {
      return (TypeAdapter) cached;
    }

    Map, FutureTypeAdapter> threadCalls = calls.get();
    boolean requiresThreadLocalCleanup = false;
    if (threadCalls == null) {
      threadCalls = new HashMap, FutureTypeAdapter>();
      calls.set(threadCalls);
      requiresThreadLocalCleanup = true;
    }

    // the key and value type parameters always agree
    FutureTypeAdapter ongoingCall = (FutureTypeAdapter) threadCalls.get(type);
    if (ongoingCall != null) {
      return ongoingCall;
    }

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

      for (TypeAdapterFactory factory : factories) {
        TypeAdapter 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 {
      threadCalls.remove(type);

      if (requiresThreadLocalCleanup) {
        calls.remove();
      }
    }
  }

我们把String 转换成实体类,通常都这么写

Gson gson = new Gson();
String strJson = "{name:"1"}";
UserBean userBean = gson.fromJson(strJson, UserBean.class);

我们来看一下fromJson这个方法

  @SuppressWarnings("unchecked")
  public  T fromJson(String json, Type typeOfT) throws JsonSyntaxException {
    if (json == null) {
      return null;
    }
    StringReader reader = new StringReader(json);
    T target = (T) fromJson(reader, typeOfT);
    return target;
  }

Gson支持以流的方式来读取字符
我们继续看源码

public  T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
    boolean isEmpty = true;
    boolean oldLenient = reader.isLenient();
    reader.setLenient(true);
    try {
      reader.peek();
      isEmpty = false;
      TypeToken typeToken = (TypeToken) TypeToken.get(typeOfT);
      TypeAdapter 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);
    } finally {
      reader.setLenient(oldLenient);
    }
  }

通过传入的类型Type,来获取这个类型对应的TypeToken
通过TypeToken来生成对应的适配器
最终转化成Object对象

Java在运行时,泛型参数的类型会被擦除,导致在运行期间所有的泛型类型都是Object类型

我们在代码中测试下:

List listStr = new ArrayList<>();

       List listInt = new ArrayList<>();

       Log.i("test-----", String.valueOf(listStr.getClass()));
       Log.i("test----", String.valueOf(listInt.getClass()));
       Log.i("test----", String.valueOf(listInt.getClass().isAssignableFrom(listStr.getClass())));

运行结果:
01-09 09:03:23.037 11017-11017/? I/test-----: class java.util.ArrayList
01-09 09:03:23.037 11017-11017/? I/test----: class java.util.ArrayList
01-09 09:03:23.037 11017-11017/? I/test----: true

说明Java运行时,泛型参数类型被擦除了

所以我再把数据转换成List型,要这么写

 Type listType = new TypeToken>(){}.getType();
        List target = new LinkedList<>();
        target.add("blah");
        List target2 = gson.fromJson(json,listType); //反序列

TypeToken 类是用来解决java运行时泛型类型被擦除的,通过TypeToken可以获得具体的参数类型
我们在代码中测试一下:

List list = new ArrayList<>();
        TypeToken> typeToken = new TypeToken>(){};
        Log.i("test------", String.valueOf(typeToken.getType()));

运行结果:
I/test------: java.util.ArrayList

你可能感兴趣的:(Gson源码分析)