在Gson的有一个JsonParser类,该类是final类型,它的作用就将json串解析成JsonElement对象。提供了三个重载方法:分别可以解析String串、Reader输入流、JsonReader输入流的方式。
简单的应用如下测试代码:

    String json = "{ \"name\":\"java书籍\", \"authors\":[\"Jerry\",\"Tom\"]}";JsonParser parser = new JsonParser();JsonElement ele = parser.parse(json);System.out.println(ele);System.out.println(ele.getAsJsonObject().get("authors").isJsonArray());

追踪parser方法:辗转调用了Stream.parser(JsonReader)方法

 public static JsonElement parse(JsonReader reader) throws JsonParseException {boolean isEmpty = true;//这是核心方法,稍后会简单说明reader.peek();isEmpty = false;return TypeAdapters.JSON_ELEMENT.read(reader);if (isEmpty) {return JsonNull.INSTANCE;}}

该方法最终执行TypeAdapter.JSON_ELEMENT.reader并返回组装好的JsonElement对象,那么就具体看看该方法都做了什么:

/***
*为TypeAdapter的静态嵌套类,实现了TypeAdapter
**/
public static final TypeAdapter<JsonElement> JSON_ELEMENT = new TypeAdapter<JsonElement>() {/*****该方法的主要作用就是让json串封装成你希望的对象,在这里是把json串*/@Override public JsonElement read(JsonReader in) throws IOException {//调用peek()方法对json传进行读取和解析,并返回对应的JsonToke类型switch (in.peek()) {case STRING://如果是字符类型,封装并返回之return new JsonPrimitive(in.nextString());case NUMBER://数字类型,例如double,long,intString number = in.nextString();return new JsonPrimitive(new LazilyParsedNumber(number));case BOOLEAN://boolean 类型:true or falsereturn new JsonPrimitive(in.nextBoolean());case NULL://nullin.nextNull();return JsonNull.INSTANCE;case BEGIN_ARRAY://数组类型//解析此数组,并添加到array中去JsonArray array = new JsonArray();in.beginArray();//循环遍历数组,并调用read方法解析成JsonElement对象,添加到array中去while (in.hasNext()) {array.add(read(in));}in.endArray();return array;//返回之case BEGIN_OBJECT://如果只json对象,例如{"name":"value"}JsonObject object = new JsonObject();in.beginObject();//解析该json对象,并获取name 和value放入object中//注意value可能是JsonElement,所以要调用read(in)while (in.hasNext()) {object.add(in.nextName(), read(in));}in.endObject();return object;case END_DOCUMENT:case NAME:case END_OBJECT:case END_ARRAY:default:throw new IllegalArgumentException();}}}

上面的方法主要是递归调用了read方法讲json串封装成JsonElement对象供我们使用,关于JsonElement的简单说明,见此博客
同时此方法也能体现出JsonElement是怎么在json的解析过程中工作的。
上面使用的JSON_ELEMENT只是TypeAdapter的一个实现类,下面让我们看看TypeAdapter这个抽象类都能做些什么。
简而言之:该类的作用就是把json串封装成你指定的Java对象!
该类的API对它的用法说明很清楚,简单的应用模板如下:

Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class,new TypeAdapter<Foo>() {public Foo read(JsonReader in) throws IOException {if (in.peek() == JsonToken.NULL) {//进行非空判断in.nextNull();return null;}//读取json串并封装成Foo对象返回之}/**** 该方法在gson.toJons(Obj)的时候会调用**/public void write(JsonWriter out, Foo src) throws IOException {if (src == null) {//进行非空判断out.nullValue();return;}//把Food对象制定成你自己定义的格式的字符串进行输出:不一定是json格式了,就看你怎么组织}}).create();

上面的使用模板都需要进行非空判断,当然如果你觉得上面的方法每次写的时候都要进行非空判断麻烦的话,也可以不写,TypeAdapter为此提供了一个优雅的解决方法:

/***
*匿名内部类的完美应用
**/public final TypeAdapter<T> nullSafe() {return new TypeAdapter<T>() {@Override public void write(JsonWriter out, T value) throws IOException {if (value == null) {out.nullValue();} else {TypeAdapter.this.write(out, value);}}@Override public T read(JsonReader reader) throws IOException {if (reader.peek() == JsonToken.NULL) {reader.nextNull();return null;}return TypeAdapter.this.read(reader);}};}

所以上面的使用方式就变成:

 Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class,new TypeAdapter<Foo>() {public Foo read(JsonReader in) throws IOException {// read a Foo from in and return it}public void write(JsonWriter out, Foo src) throws IOException {// write src as JSON to out}}.nullSafe()).create();

其实,在我们调用gson的fromJson(String,class)方法的时候,沿着方法调用的路径::fromJson(String,Class)–>fromJson(String,Type) (Type包含了class的报名和类名 class package.className)–>fromJson(Reader,Type)–>fromJson(JsonReader,Type);最终调用了fromJson(Jsonreader,Type):

 public <T> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {reader.peek();isEmpty = false;TypeToken<T> typeToken = (TypeToken<T>) TypeToken.get(typeOfT);TypeAdapter<T> typeAdapter = getAdapter(typeToken);//此处正是你自定义的Adapter方法或者Gson自带的Adapter的用武之地。T object = typeAdapter.read(reader);return object;}

当然自定义的Adapter是怎么让Gson使用的,需要调用registerTypeAdapter方法,把你自定义的Adapter注册进去:

public GsonBuilder registerTypeAdapter(Type type, Object typeAdapter) {//此处有省略代码if (typeAdapter instanceof TypeAdapter<?>) {//至于TypeToken后面会另起篇幅进行说明//把你的Adapter和传入的type重新封装成TypeAdapterFactory并加入到factories中去。factories.add(TypeAdapters.newFactory(TypeToken.get(type), (TypeAdapter)typeAdapter));}return this;}

正如证明代码所示,先把自定义的Adapter和Type封装成TypeAdapterFactory对象,然后添加到factories这个List集合中去,对于TypeAdapterFactory的说明,会另起篇幅进行说明。然后调用GsonBuilder.create()方法创建Gson对象:

public Gson create() {List<TypeAdapterFactory> factories = new ArrayList<TypeAdapterFactory>();//把GsonBuilder的factories 传入到新定义的factories 中并交给Gson处理。factories.addAll(this.factories);Collections.reverse(factories);factories.addAll(this.hierarchyFactories);addTypeAdaptersForDate(datePattern, dateStyle, timeStyle, factories);return new Gson(excluder, fieldNamingPolicy, instanceCreators,serializeNulls, complexMapKeySerialization,generateNonExecutableJson, escapeHtmlChars, prettyPrinting,serializeSpecialFloatingPointValues, longSerializationPolicy, factories);}

从上面的fromJson(JsonReader,type)方法中,先调用getAdapter(typeToken)方法获取到Adapter,当然也包含你自定义的Adapter:

  private final Map<TypeToken<?>, TypeAdapter<?>> typeTokenCache= Collections.synchronizedMap(new HashMap<TypeToken<?>, TypeAdapter<?>>());private final ThreadLocal<Map<TypeToken<?>, FutureTypeAdapter<?>>> calls= new ThreadLocal<Map<TypeToken<?>, FutureTypeAdapter<?>>>();public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {//从typeTokenCache获取对应的TypeAdapterTypeAdapter<?> cached = typeTokenCache.get(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;}//FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type);if (ongoingCall != null) {return ongoingCall;}try {FutureTypeAdapter<T> call = new FutureTypeAdapter<T>();threadCalls.put(type, call);//遍历Gson的factories集合,其中你的Adapter封装后的TypeAdapterFacotry也在里面。for (TypeAdapterFactory factory : factories) {//重新从你封装过后的TypeAdapterFacotry获取到之前封装过后的AdapterTypeAdapter<T> candidate = factory.create(this, type);if (candidate != null) {//设置代理,这个在之后的博客说明call.setDelegate(candidate);//放入缓存中typeTokenCache.put(type, candidate);return candidate;}}throw new IllegalArgumentException("GSON cannot handle " + type);} finally {threadCalls.remove(type);if (requiresThreadLocalCleanup) {calls.remove();}}}

到此为止TypeAdapter的工作方式已经说明了,现在总结一下:
1)通过GsonBuilder注册TypeAdapter,并把TypeAdapter封装成TypeAdpterFactory对象
2)将封装成的TypeAdapterFactory通过GsonBuilder的create传入Gson对象中并返回
3)调用gson.fromJson方法,调用getTypeAdapter方法返回你自定义的Adapter,并调用其reader方法进行处理!

最后在看看TypeAdapter这个抽象类的两个抽象方法,就能明白TypeAdapter的作用了:

public abstract class TypeAdapter<T> {public abstract void write(JsonWriter out, T value) throws IOException;public abstract T read(JsonReader in) throws IOException;}

其中reader的主要作用就是让读取的json转换成指定类型的对象T,write则是让T对象转换成一个json.

最后盗用两个图说明Adapter的工作原理(此为盗图链接):

可参考资料:

Gson之TypeAdapter的工作原理分析(1)相关推荐

  1. RxJs map operator 工作原理分析

    使用一个例子来研究 map 操作符的工作原理. 推荐阅读本文之前,先浏览这篇文章RxJs fromEvent 工作原理分析以了解相关知识. 源代码: import { Component, OnIni ...

  2. Hadoop生态圈-Zookeeper的工作原理分析

    Hadoop生态圈-Zookeeper的工作原理分析 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.   无论是是Kafka集群,还是producer和consumer都依赖于Zoo ...

  3. 原理剖析(第 009 篇)ReentrantReadWriteLock工作原理分析

    2019独角兽企业重金招聘Python工程师标准>>> 原理剖析(第 009 篇)ReentrantReadWriteLock工作原理分析 一.大致介绍 1.在前面章节了解了AQS和 ...

  4. 匿名突破网络限制 (Tor工作原理分析)

    转载自:http://blog.163.com/mike_gz/blog/static/247532200672932800/ 网管顾名思义,就是天天管着网络.想尽各种手段限制我们上网的人.在网络中订 ...

  5. 滑环的基本结构及工作原理分析

    滑环是工业机械部件,基本原理是利用导电机械部件的折动或滚动在接触旋转部件和静止部件之间传递电能或电信号的产业部部件,作为360度旋转方式的一个相当好的解决方法,那么,下面一起了解下滑环的基本结构及工作 ...

  6. 【高通SDM660平台 Android 10.0】(19) --- Camera_focus、Camera_snapshot、volume_up 按键工作原理分析

    [高通SDM660平台 Android 10.0]19 --- Camera_focus.Camera_snapshot.volume_up 按键工作原理分析 一. DTS代码配置 二. Kernel ...

  7. 二极管温度补偿电路工作原理分析

    众所周知,PN结导通后有一个约为0.6V(指硅材料PN结)的压降,同时PN结还有一个与温度相关的特性:PN结导通后的压降基本不变,但不是不变,PN结两端的压降随温度升高而略有下降,温度愈高其下降的量愈 ...

  8. 船型开关工作原理分析

    船型开关工作原理分析 由于疫情,这几个月一直无聊的待在家里,就把家里翻出来的旧电热锅简单的修理了一下,关于电热锅的修理博客之后有时间再写吧,这次就总结下在修过程中让我一直很头疼的船型开关的工作原理. ...

  9. 全自动升降柱工作原理分析

    全自动升降柱工作原理分析 全自动升降柱使用范围比较广泛,在城市交通安全中提供非常便捷的交通舒缓措施,可控制车辆行驶确保安全,全自动升降柱外观设计精美, 具有高的防撞击效果,当电动升降柱升起可在地面形成 ...

  10. 结合 category 工作原理分析 OC2.0 中的 runtime

    绝大多数 iOS 开发者在学习 runtime 时都阅读过 runtime.h 文件中的这段代码: struct objc_class {Class isa OBJC_ISA_AVAILABILITY ...

最新文章

  1. 数据链路层协议_数据链路层 基本数据链路协议
  2. DeprecationWarning Mongoose mpromise (mongoose's default promise li
  3. 在对比了 GitHub 5000 个 Python 项目之后,我们精选出了这 36 个!
  4. comsol 多物理场仿真流程-以开关柜为例
  5. eclipse支持html,让eclipse完全支持HTML/JS/CSS智能提示
  6. android之uniapp弹出activity
  7. Java 虚拟机简介
  8. spss26没有典型相关性分析_如何在SPSS中实现典型相关分析
  9. linux开发板访问互联网 笔记本win10中虚拟机
  10. 参考文献格式字号字体_参考文献标准格式字体
  11. 【美影】通灵男孩诺曼.Paranorman
  12. uni-app编译报caniuse-lite is outdated
  13. atitit html5 拼图游戏的解决之道
  14. C语言编写实现玫瑰花
  15. Mac下Qt for android 环境配置
  16. 迅捷画图中套用流程图模板编辑方法介绍
  17. 用Python绘制K线图
  18. 【大一年度总结与展望未来】一个普通双非的大学生
  19. 梅特卡夫法则(Metcalfe's law)
  20. 空客设立多个零碳研究机构 致力设计制造氢动力飞机

热门文章

  1. Sass:基础用法学习笔记
  2. 爬虫:python爬虫学习笔记之Beautifulsoup正则表达式
  3. Java自然语言处理NLP工具包
  4. 算法面试_怎么简单高效的理解递归?//TODO
  5. 关于目前深度学习技术的相关思考----个人理解笔记
  6. 【直观详解】信息熵、交叉熵和相对熵
  7. opencv中的Mat、CvMat以及IplImage介绍以及三者之间的转换
  8. [论文评析] ArXiv-2021,Pyramid Vision Transformer A Versatile Backbone for Dense Prediction without Convo
  9. 跟我一起学QT_QT标准对话框_颜色选择框
  10. 类方法实现:用python实现一个简单的单词本,添加/查找/删除单词。