美文网首页gson
Gson源码分析

Gson源码分析

作者: wervy | 来源:发表于2019-12-18 14:52 被阅读0次

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

image.png

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


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

关于TypeToken的问题

Type listType = new TypeToken<List<String>>(){}.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 <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
    TypeAdapter<?> cached = typeTokenCache.get(type == null ? NULL_KEY_SURROGATE : type);
    if (cached != null) {
      return (TypeAdapter<T>) cached;
    }

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

      for (TypeAdapterFactory factory : factories) {
        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 {
      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> 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> 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<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);
    } finally {
      reader.setLenient(oldLenient);
    }
  }

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

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

我们在代码中测试下:

List<String> listStr = new ArrayList<>();

       List<Integer> 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<List<String>>(){}.getType();
        List<String> target = new LinkedList<>();
        target.add("blah");
        List<String> target2 = gson.fromJson(json,listType); //反序列

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

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

运行结果:
I/test------: java.util.ArrayList<java.lang.String>

相关文章

  • GSON源码分析

    使用GSON库很久,但一直没有深入分析它的内部实现机理。正好为了建立团队java开发规范,参考了google的ja...

  • Gson源码分析

    Gson在Android开发中,我们经常用到,主要用于把服务端给我们返回的json字符串,解析成相应的实体类,我们...

  • 1.gson-plugin告别Json数据类型不一致(一)

    一、目录 1.gson-plugin告别Json数据类型不一致(一)2.gson-plugin基础源码分析(二)3...

  • Gson源码分析(三)

    Gson解析给我满带来了很多方便,但其实,Gson可以更方便,接下来就介绍Gson的两个特殊功能,这两个功能也是在...

  • Gson源码分析(一)

    Json解析一直是网络通信中重要的数据解析框架。而Gson和FastJson是最为常用的两个Json解析框架。这一...

  • Gson源码分析(二)

    Gson解析后的数据一般不会是String类型,而是Object(的子类)或者Array(广义)类型。先从Obje...

  • Gson源码分析——(壹)泛型

    Gson是Google提供的一套用于解析Json数据的工具库。本人之前其实写过关于Gson源码分析的文章,但由于当...

  • okhttp遇到的一点问题汇集

    参考资料 OkHttp-官方资料Okhttp源码分析以及Google Gson解析json数据实例-respons...

  • Gson源码分析——(贰)初探

    基于非墨上一篇关于泛型的文章,不知道大家是否已经做好了阅读Gson源码的准备?本篇文章,非墨将简单带大家过一下Gs...

  • 网络编程-Gson源码分析

    https://juejin.im/post/6854573216178896910

网友评论

    本文标题:Gson源码分析

    本文链接:https://www.haomeiwen.com/subject/axbynctx.html