IT学习站-137zw.com

more +资源更新Forums

more +随机图赏Gallery

Java程序员面试笔试真题与解析 完整pdf扫描版Java程序员面试笔试真题与解析 完整pdf扫描版
价值348元 RabbitMQ消息中间件技术精讲2018视频教程 百度云价值348元 RabbitMQ消息中间件技术精讲2018视频教程 百度云
10节课让你成为滚床单高手  强烈推荐 屌丝的福音10节课让你成为滚床单高手 强烈推荐 屌丝的福音
Spring Boot编程思想(核心篇) PDF 电子书 百度云 网盘下载Spring Boot编程思想(核心篇) PDF 电子书 百度云 网盘下载
最新流出的传智博学谷黑马python5.0课程最新流出的传智博学谷黑马python5.0课程
MySQL视频教程价值288元MySQL面试指南视频教程 百度云 百度...MySQL视频教程价值288元MySQL面试指南视频教程 百度云 百度...

除了FastJson,你还有选择: Gson简易指南

除了FastJson,你还有选择: Gson简易指南

[复制链接]
哈哈SE7 | 显示全部楼层 发表于: 2019-11-14 12:30:00
哈哈SE7 发表于: 2019-11-14 12:30:00 | 显示全部楼层 |阅读模式
查看: 102|回复: 0
前言

这个周末被几个技术博主的同一篇公众号文章 fastjson又被发现漏洞,这次危害可导致服务瘫痪! 刷屏,离之前漏洞事件没多久,fastjson 又出现严重 Bug。目前项目中不少使用了 fastjson 做对象与JSON数据的转换,又需要更新版本重新部署,可以说是费时费力。与此同时,也带给我新的思考,面对大量功能强大的开源库,我们不能盲目地引入到项目之中,众多开源框架中某个不稳定因素就足以让一个项目遭受灭顶之灾。趁着周末,在家学习下同样具备JSON与对象转换功能的优秀开源框架 Gson,并且打算将今后项目使用 fastjson 的地方逐渐换成使用 Gson,记录下学习总结的内容,希望对小伙伴也有所帮助。
本文所涉及所有代码片段均在下面仓库中,感兴趣的小伙伴欢迎参考学习:
https://github.com/wrcj12138aaa/gson-actions
版本支持:

  • JDK 8
  • Gson 2.8.5
  • JUnit 5.5.1
  • Lomok 1.18.8
Gson 简介

在正式介绍 Gson 之前,我们可以先从官方的wiki看下 Gson 的描述,了解它是什么?
Gson is a Java library that can be used to convert Java Objects into their JSON representation. It can also be used to convert a JSON string to an equivalent Java object。
从描述可以看出,Gson 是用于将 Java 对象与 JSON格式字符串数据相互转换的 Java 库。它起初在Google 内部广泛使用在 Android 平台 和 Java 服务端上。2008 年开源之后,成为了谷歌又一个被广泛使用的开源框架,截止目前(2019.09.08) 在GitHub 上已有1W6 多星,相同作用的类库还有 Spring Framework 中集成的 Jackson,以及阿里开源的 fastjson等。
在特性方面,Gson 提供简易的API fromJson/toJson 来实现 Java 与 JSON 之间的转换,并且能生成紧凑,可读的 JSON 字符串输出,还支持复杂对象转换和丰富的自定义表示,足以满足在日常开发中我们绝大部分的 JSON 数据处理需求。
我们通常将对象与JSON字符串间的转换称之为序列化和反序列化(Serialization/Deserialization)。将 对象转化成 JSON字符串的过程称为序列化,将JSON 字符串转化成对象的过程称为反序列化。
除了FastJson,你还有选择: Gson简易指南  技术博客 664672-20190909210407732-1069533558

Gson 基本使用

使用 Gson 框架进行序列化与反序列操作,都离不开 com.google.gson.Gson 对象,它也是 Gson 框架的关键对象,提供的公共 API 具备了多种序列化和反序列方式。
除了FastJson,你还有选择: Gson简易指南  技术博客 664672-20190909210409686-1751213802

Gson 对象的创建主要有两种方式:

  • 使用 new 关键字直接创建:Gson gson = new Gson()
  • 由 GsonBuilder 对象构建:Gson gson = new GsonBuilder().create()
通常情况下,上面两种方式创建的 Gson 对象在进行序列化与反序列操作时行为都是一样的,但是第二种方式构建 Gson 对象时,允许进行额外的行为定制,比如格式化 JSON 字符串的输出内容,是否序列化 null 值等等。
Java 序列化

简单对象的序列化

我们可以通过下面的例子来看下通过上述两种方式序列化 Java 对象的不同效果:运行该测试用例,在控制台可以看到如下日志输出:
除了FastJson,你还有选择: Gson简易指南  技术博客 664672-20190909210410149-697475905

从结果可以看出,默认的 Gson 对象行为序列化对象时会将 null 值的字段忽略,而 com.google.gson.GsonBuilder#serializeNulls 方法将允许 Gson 对象序列化 null 字段;并且正常序列化后的 JSON 字符串是紧凑格式,节省字符串内存,使用 com.google.gson.GsonBuilder#setPrettyPrinting 方法之后最终输出的 JSON 字符串是更易读的格式。当然除了这两个方法,GsonBuilder 还提供了许多定制序列化和反序列化行为的API,我们将后面的内容进一步讲解。
JosnObject 生成 JSON

除了上述将自定义类的对象转换成 JSON 的方式之外,还可以使用 Gson 框架提供的 JsonObject 构建普通对象,然后使用 toJson 方法生成 JSON 字符串,在原测试类中补充下方测试类,并运行查看效果如下JsonObject 使用 addProperty(property,value) 方法只能用来添加 String,Number,Boolean,Character这四类数据, 因为内部是调用 com.google.gson.JsonObject#add, 将 value 封装成了 JsonPrimitive 对象,然后保存到了内部自定义的 LinkedTreeMap 集合变量 members 中;如果需要在 JsonObject 对象上添加其他对象时,就需要直接使用 add(String property, JsonElement value) 方法添加一个 JsonElement 对象。这里的 JsonElement 是一个抽象类,JsonObject 和 JsonPrimitive 都继承了JsonElement,所以我们最终通过另外的 JsonObject 对象来作为原 JsonObject 上的属性对象:JSON 反序列化

简单对象的反序列化

现在我们再来看下 JSON 反序列化成 Java 对象用法,这里主要使用方法是 com.google.gson.Gson#fromJson,它最基础的用法就是 fromJson(String json, Class classOfT),尝试将 JSON 字符串转为指定 Class 的对象,如果转换失败,就会抛出 JsonSyntaxException 异常。我们可以在原来代码上新增一个测试用例,运行看下效果:反序列化 Map

除了将JSON 字符串序列化为自定义的Java 对象之外,我们还可以转为 Map 集合,Gson 提供了对 Map 集合的转换,使用起来也十分简单:需要注意的是转换后的 Map 对象真实类型并不是我们经常用的 HashMap,而是 Gson 自定义集合LinkedTreeMap ,它实现Map 接口来存储键值对,在新增和删除上实现上进行了优化,并且将存储键值对的顺序作为遍历顺序,也就是先存入的先被遍历到。除此之外,JSON 字符串里的数值型数据都会转转换为 Double 类型,而 true/false 数据被会被转换成 Boolean 类型,具体判断依据可以参考 com.google.gson.internal.bind.ObjectTypeAdapter#read 方法的实现。
JSON 与 Array,List 转换

JSON 转换 Array

当我们正对 JSON 数据进行数组转换时,类似普通对象转换的方式即可, toJson 方法直接使用转为 JSON 数据,fromJson 指定数组类型转换为对应类型的数组。JSON 转换 List

要将 List 数据转换为 JSON数据,使用 Gson 的方式与处理 Array 数据一样;这里主要讲的是将JSON 数据转为 List 对象的操作略有不同,要将一个 JSON 数组数据转换为一个自定义类的List 时,我们按照原来的写法如下:但是不幸的是,运行这段代码后会抛出 ClassCastException 异常,具体描述如下:从上述描述中我们可以知道执行 fromJson 之后,反序列化后得到的 List 元素类型为 LinkedTreeMap,而不是 Person,所以以 Person 对象方式访问 id 属性时就会抛出 ClassCastException 异常。那又该如何处理呢, 我们需要调用 Gson 的 另外一个 fromJson 方法:fromJson(String json, Type typeOfT) ,先看下使用方式这个方法中的 Type 对象通过 TypeToken 对象的 getType 方法获取到,就是 TypeToken 对象所关联的泛型类型。而这里 TypeToken 是 Gson 为了支持泛型而引入的类,来解决 Java 无法提供泛型类型表示的问题,由于 TypeToken 的构造方法是protected修饰的,无法直接构造,使用就需要写成new TypeToken() {}.getType() 形式。
Gson 进阶用法

接触了 Gson 基本的使用之后,我们接着进一步学习 Gson 的其他用法。
泛型对象的反序列化

上节内容简单接触了 Gson 对泛型的支持,接下来用代码来展示下它的强大之处,首先我们将上文的 Result 类调整下接受泛型参数:然后对一个有内嵌对象的 JSON字符串进行解析成 Result 对象,示例代码如下:利用 TypeToken 对象获取具体泛型类型 Result , 然后在 fromJson 方法中传入就会根据对应类型的执行反序列化操作。
自定义序列化

如果我们要对Java 对象的某些字段进行特殊处理,比如隐藏某些字段的序列化,对字段的数据格式化处理等,我们可以通过实现 JsonSerializer 接口,对序列化逻辑进行自定义。例如,我们需要对 Date 类型属性进行特定格式的处理,可以声明 DateSerializer 类实现如下:然后在构建 Gson 对象前,利用 GsonBuilder 将 DateSerializer 实例进行注册,使用方式如下:这样一来,一旦遇到要序列化 Date 类型的字段时,都会通过自定义的 serialize 方法将日期以 yyyy-MM-dd 格式进行输出,如下方的示例代码:自定义反序列化

与自定义序列化实现方式类似,想要自定义反序列化逻辑,就需要同样要实现一个叫 JsonDeserializer 的接口,进行自定义反序列化逻辑的实现。比如现在有个 JSON 字符串内容为 {"CODE": 400, "MESSAGE": "参数错误"},需要被反序列化为前文提到的 Result 对象,由于字段名不一样,为了实现对应的转换,就需要自定义 ResultDeserializer 类,具体实现如下:接下来就是利用 GsonBuilder 注册 ResultDeserializer 实例,生成对应的 Gson 对象,并进行反序列化操作:Gson 常用注解

Gson 除了提供一些 API 供开发者使用之外,还有一些具有特性的注解可以使用,接下来就介绍在 Gson 中最常用的注解。
@Expose

这个注解只能用在字段上,作用就是注明对应的字段是否将在序列化或者反序列化时暴露出来,有两个属性 serialize 和 deserialize ,默认都为 true。当给一个字段加上 注解@Expose(serialize = true, deserialize = false),则表示了该字段尽在序列化时可见,在反序列化时会忽略赋值。需要额外注意的一点是,@Expose 注解只有在用 GsonBuilder 方式构建 Gson 时有限,并且构建前必须调用 excludeFieldsWithoutExposeAnnotation 方法,下面是具体的使用示例:
在 Gson 中 transient 关键字修饰的字段默认不会被序列化和反序列化,这个行为是与 Java 原生的序列化和反序列化操作一致的。
@Since

该注解用于标记对应字段或者类型的版本,让 Gson 可以指定版本号进行序列化和反序列化操作。当Web服务上的 JSON 数据对应的类存在多个版本的字段时,这个注解就十分有用。
同样地,该注解只针对使用 GsonBuilder 方式构建的 Gson 对象,并且使用 setVersion 方法指明版本号时有效,只解析对象中对应版本的字段,下面为具体示例:@SerializedName

这个注解使用起来比较简单,也很有用。@SerializedName 指定了成员字段被序列化和反序列化时所采用的名称下面是具体使用方式:@JsonAdapter

不同于上面的注解,@JsonAdapter 只作用于类上,主要作用就是代替 GsonBuilder.registerTypeAdapter 方法的执行,直接通过 @JsonAdapter(aClass.class) 方式指定 JsonDeserializer 对象或者 JsonSerializer 对象,可以起到相同的想过,并且优先级比GsonBuilder.registerTypeAdapter的优先级更高,由于只是将 registerTypeAdapter方法执行简化成了注解方法,这里就不再演示,直接在前文自定义反序列化一节的 Result 类上使用就可以看到效果。
结语

本文主要学习总结了 Gson 框架的序列化和反序列操作使用方式,以及介绍了 Gson 多种特性用法,希望对处理 JSON 数据感到头疼的小伙伴有所帮助。
除了FastJson,你还有选择: Gson简易指南  技术博客 664672-20190909210410645-1512437898

推荐阅读

参考资料


  • https://github.com/google/gson/blob/master/UserGuide.md
  • https://www.jianshu.com/p/e740196225a4
  • https://juejin.im/post/5aad29f8518825558453c6c9
  • https://www.baeldung.com/gson-deserialization-guide
  • https://www.baeldung.com/gson-string-to-jsonobject

来源:http://www.137zw.com
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
137zw.com IT学习站致力于免费提供精品的java技术教程和python技术教程,CCNA书籍/资料/CCNP书籍/资料教程/CCIE书籍/资料/H3C学习/认证/一级建造师考试/微软学习/认证/包括基础教程和高级实战教程,同时也提供分享网站源码下载和互联网相关一系列的技术教程,我们想做的就是让知识分享更有价值!(IT学习站官方唯一域名地址:www.137zw.com 请谨防假冒网站!)本站所有资源全部收集于互联网或网友自行分享,分享目的仅供大家学习与参考,如无意中侵犯您的合法权益,请联系本站管理员进行删除处理!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐上一条 /1 下一条

浙ICP备19022368号-1|Archiver|手机版|IT学习站-137zw.com

GMT+8, 2020-7-11 00:02 , Processed in 2.815119 second(s), 34 queries .

快速回复 返回顶部 返回列表