Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >如何更好的使用Gson

如何更好的使用Gson

原创
作者头像
Jackeyzhe
修改于 2020-06-15 02:58:46
修改于 2020-06-15 02:58:46
1.6K0
举报
文章被收录于专栏:代码洁癖患者代码洁癖患者

最近工作比较忙,很久没更新了,先向大家道个歉。

今天想分享一些工作中遇到的关于gson的坑,这么说其实不太准确,因为不能算是gson的坑,更多的是因为旧代码产生了一些不规范的数据导致使用gson时遇到了一些问题。

gson简介

可能有的同学不了解gson,所以在分享坑之前先来介绍一下gson,已经熟练使用gson的同学可以直接跳到下一部分了。gson是Google开源的一个Java序列化库,它具有以下特点:

  • 使用简单,只需要掌握toJson()fromJson()两个方法就可以实现Java对象和JSON字符串之间的序列化和反序列化
  • 允许将现有的不可修改的对象与JSON互相转换
  • 对Java的泛型支持的很好
  • 允许自定义一些对象的表现形式
  • 支持复杂对象的序列化
使用gson

那现在我们就来体验一下gson的第一个特性,使用简单。由团队中成员的能力参差不齐,所以一个简单易用性对这种基础组件是非常重要的。

在使用gson之前,我们需要添加依赖,我们的项目中使用的是Maven管理依赖,所以会在pom.xml文件中插入以下代码:

代码语言:txt
AI代码解释
复制
<dependency>
  <groupId>com.google.code.gson</groupId>
  <artifactId>gson</artifactId>
  <version>2.8.6</version>
</dependency>

如果你的项目使用的是Gradle管理依赖,你需要新增下面的代码

代码语言:txt
AI代码解释
复制
dependencies {
  implementation 'com.google.code.gson:gson:2.8.6'
}

依赖添加好以后,就可以直接开始使用了,这里我先来定义一个简单的POJO类(原谅我直接使用@Data)。

代码语言:txt
AI代码解释
复制
import lombok.Data;

@Data
public class User {

    private String name;

    private Integer age;

    private String email;

    private Boolean isVip;
}

接着就可以体验gson了,直接看一个demo吧。

代码语言:txt
AI代码解释
复制
public class GsonTest {

    public static void main(String[] args) {
        User user = new User();
        user.setName("Jackey");
        user.setAge(18);
        user.setEmail("Jackeyzhe59@gmail.com");
        user.setIsVip(true);
        Gson gson = new Gson();
        String json = gson.toJson(user);
        System.out.println(json);

        User u = gson.fromJson(json, User.class);
        System.out.println(u.getName());
    }
}

来看一下输出结果

结果.png
结果.png

完美!是不是非常简单?

那现在我们已经学会gson的基础用法了,接下来就进入正题,分享几个我在使用过程中遇到的实际问题以及解决方案。

案例分享

null转为空字符串

在我们的使用过程中,遇到过这样的情况对于一个对象,在做序列化的时候,如果遇到了某个item为null,那么gson序列化出来的结果中就不会包含这个属性,这看起来很合理,不过对于我们的项目而言,前端同学需要根据有没有这个item来展示不同的信息,如果有这个item,但是值为空,那么前端就展示「不能告诉你」,如果没有这个item,前端同学就会展示为「没有这个item」。这么说可能令人有些费解,我们还是通过上面的例子来看。

代码语言:txt
AI代码解释
复制
{
    "age":18,
    "email":"Jackeyzhe59@gmail.com",
    "isVip":true
}

如果我把name设置为null,那么序列化的结果就是这样。此时前端就会展示为「用户没有姓名信息」,如果我把name设置成空字符串,那么序列化结果就会不同。

代码语言:txt
AI代码解释
复制
{
    "name":"",
    "age":18,
    "email":"Jackeyzhe59@gmail.com",
    "isVip":true
}

这时我们的前端同学就会告诉用户,此用户不想展示名称。

我们现在想要避免出现第一种情况,虽然说可以约定不能把name设置为null,但是这种约定就很容易导致bug的产生,尤其是对于刚刚加入团队的新同学来说,他们可能会在不经意间就做了这样一个操作,在code review的时候也可能会出现遗漏。因此我选择定义一种TypeAdapter来约束我们序列化的工作。

这里可以先介绍一下gson中TypeAdapter的使用方法,TypeAdapter可以帮助我们自定义序列化/反序列化方式,它的使用也比较简单,首先我们需要定义一个自己的Adapter类,让它继承TypeAdapter类

代码语言:txt
AI代码解释
复制
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;

public class StringNullAdapter extends TypeAdapter<String> {

    @Override
    public void write(JsonWriter out, String value) throws IOException {
        if (value == null) { // 序列化使用的是adapter的write方法
            out.value("");
            return;
        }
        out.value(value);
    }

    @Override
    public String read(JsonReader in) throws IOException {
        if (in.peek() == JsonToken.NULL) { // 反序列化使用的是read方法
            in.nextNull();
            return "";
        }
        return in.nextString();
    }
}

然后自己重写read和write方法,这里我们需要的是write方法。

其中参数value就是传入的对象属性,我们判断它是null,就将其转化为空字符串。

写好Adapter类之后,我们在新建gson的时候需要注册我们刚刚定义的Adapter。

代码语言:txt
AI代码解释
复制
Gson gson = new GsonBuilder()
            .registerTypeAdapter(String.class, new StringNullAdapter())
            .create();

GsonBuilder提供了registerTypeAdapter这个方法,可以直接为String类型都注册上我们自己的Adapter。

这时再将name设置为null,序列化结果就是我们期望的结果了。

数字和Boolean到底用哪个

我们在开发过程中还遇到了这样一个问题,在和另一个node写的服务做交互时,我们发现,node服务返回给我们的JSON对应的Boolean类型字段的值是0或1。

还用我们前面的例子来讲,如果node服务返回给我们的数据是这样的json字符串

代码语言:txt
AI代码解释
复制
{
    "name":"Jackey",
    "age":18,
    "email":"Jackeyzhe59@gmail.com",
    "isVip":1
}

那么我们在反序列化时就会报错

报错信息
报错信息

错误信息写的很清楚,我们的isVip字段是一个Boolean类型的,但是json中却是数字类型,gson没办法识别了。

这时我们可以让node服务来修改,也可以选择自己做适配。

自己做适配的话,有两种方式,一种是把isVip字段改成Number类型,但是由于isVip只可能存在两种值(是/否),用Number类型不是很合适。另一种方式就是再写一个Adapter来做适配,这次我们就需要重写read方法了。

代码语言:txt
AI代码解释
复制
public Boolean read(JsonReader in) throws IOException {
  JsonToken peek = in.peek();
  switch (peek) {
    case BOOLEAN:
      return in.nextBoolean();
    case NULL:
      in.nextNull();
      return null;
    case NUMBER:
      return in.nextInt() != 0;
    case STRING:
      return Boolean.parseBoolean(in.nextString());
    default:
      throw new IllegalStateException("Expected BOOLEAN or NUMBER but was " + peek);
  }
}

针对我们的问题,只需要处理NUMBER类型就可以了,不过这里我还兼容了STRING类型,把字符串的true/false转换成Boolean类型。你可以根据业务需要自行适配。例如有些团队可能会将null值认为是false,这里直接修改一下就好。

写好了Adapter以后还是别忘了注册。

扩展一点

细心的同学一定注意到了JsonToken这个类了,这是gson中对于Json符号类型的定义。它包含以下几种

  • BEGIN_ARRAY
  • END_ARRAY
  • BEGIN_OBJECT
  • END_OBJECT
  • NAME
  • STRING
  • NUMBER
  • BOOLEAN
  • NULL
  • END_DOCUMENT

从名称上就可以分辨出来BEGIN_ARRAYEND_ARRAY是对数组的标记,BEGIN_OBJECTEND_OBJECT是对对象的标记,NAME标记的是json中的「key」,STRINGNUMBERBOOLEANNULL都是json中值的类型,END_DOCUMENT是json流结束的标识。

讨论

最后留一个问题大家可以和我一起讨论,我们在做反序列化时还遇到了BT的字符串的null,它本身所属的字段是Map类型,这样的Adapter应该怎么写呢?

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
从Gson 的一个著名Bug说起
Gson是一个源自谷歌的JSON序列化/反序列化框架,出身名门,社区活跃,因此被广泛应用。
Antony
2021/07/14
2.1K0
从Gson 的一个著名Bug说起
人生苦短,我用Gson
JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式。它基于 ECMAScript (w3c制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。 JSON 键值对是用来保存JS对象的一种方式,和JS对象的写法也大同小异,键/值对组合中的键名写在前面并用双引号 “” 包裹,使用冒号 : 分隔,然后紧接着值,如下例子所示:
你呀不牛
2021/05/28
2.2K0
Android Study 之 彻底解决 Gson解析 异常 :JsonSyntaxException
开发过程中,App常用的接收参数的时候,几乎大部分都是以json格式为主,那么有关解析json的方式有很多,Android端相对来说使用Gson比较多,而在解析过程中,如果你遇到规范的后台,那你大可放心随便浪,But,如果遇到神后台,那么,呵呵了你就。真的想不到还会出现什么问题。。。
贺biubiu
2019/06/10
4.6K0
Gson如何自定义Calendar序列化/反序列化
发现birthday最终实例化后,类型是 GregorianCalendar(即:抽象类Calendar的子类),然后把刚才的代码略改了下:
菩提树下的杨过
2022/04/27
8960
Gson如何自定义Calendar序列化/反序列化
SpringMVC+GSON 对象序列化--日期格式的处理
Gson异常强大因此使用它代替了Jackson作为SpringMVC消息转换器。 在自己的项目中,发现对象在序列化后,日期格式出现了问题。 先看问题 在员工表中有一列是生日,字段类型为Date,也就是
用户2193479
2018/06/28
2.5K0
Google Gson用法详解
Gson(又称Google Gson)是Google公司发布的一个开放源代码的Java库,主要用途为序列化Java对象为JSON字符串,或反序列化JSON字符串成Java对象。
三分恶
2020/07/16
22.3K2
Android 序列化框架 Gson 原理分析,可以优化吗?
Gson[1] 是 Google 推出的 Java Json 解析库,具有接入成本低、使用便捷、功能扩展性良好等优点,想必大家都很熟悉了。在这篇文章里,我们将讨论 Gson 的基本用法和以及主要流程的源码分析。
用户9995743
2022/12/22
2.5K0
Android 序列化框架 Gson 原理分析,可以优化吗?
魔改 TypeAdapterFactory
感慨:Retrofit2 虽好,但是,有时候总感觉 Java 这门语言还是美中不足啊!
HelloVass
2018/09/12
2K0
Gson的学习与使用
GSON是Google提供的用来在Java对象和JSON数据之间进行映射的Java类库。可以将一个Json字符转成一个Java对象,或者将一个Java转化为Json字符串。
用户1134788
2022/05/09
1.6K0
Gson的学习与使用
Gson 解析 Json 容错才是关键,举几个常用的实例!
Gson是一个Java库,它不仅可以把Java对象转化为Json格式,它也能将一段Json格式的字符串转化为相对于的Java对象。 Gson适用于所有Java对象,即使是那些你不知道源代码的对象。
Android技术干货分享
2019/07/01
3.4K0
Gson 解析 Json 容错才是关键,举几个常用的实例!
gson参数走私浅析
Gson 是一个由 Google 开发的 Java 库,用于将 Java 对象序列化为 JSON 格式,以及将 JSON 字符串反序列化为 Java 对象。Gson 以其简单易用和高性能而闻名,它提供了一种非常直观的方式来处理 JSON 数据。浅析其中潜在的参数走私场景。
亿人安全
2024/11/26
1520
gson参数走私浅析
大型项目废弃fastjson迁移至Gson保姆级攻略
在被大家取关之前,我立下一个“远大的理想”,一定要在这周更新文章。现在看来,flag有用了。。。
蛮三刀酱
2021/01/13
1.9K0
如何编写一个JSON解析器
编写一个JSON解析器实际上就是一个函数,它的输入是一个表示JSON的字符串,输出是结构化的对应到语言本身的数据结构。
bear_fish
2018/09/20
9730
如何编写一个JSON解析器
采用Gson解析含有多种JsonObject的复杂json
https://github.com/sososeen09/MultiTypeJsonParser
陈宇明
2020/12/15
2.5K0
采用Gson解析含有多种JsonObject的复杂json
Gson 笔记
要使用GSON库,Gson类需要实例化一个 com.google.GSON 的对象。GSON对象不维护任何状态,这个特性有助于在多个地方重用GSON对象。
Remember_Ray
2020/03/09
3.8K0
Android框架-Google官方Gson解析
而 JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成,广泛应用于各种数据的交互中,尤其是服务器与客户端的交互。
Android技术干货分享
2019/03/26
1.1K0
Android框架-Google官方Gson解析
Gson基本使用
Gson是谷歌官方推出的支持 JSON -- Java Object 相互转换的 Java序列化/反序列化 库,之前由于没有用过,所以学习一下。
阿超
2022/08/16
5880
Gson基本使用
SpringBoot的序列化和反序列化
Java序列化是指把Java对象转换为字节序列的过程,而Java反序列化是指把字节序列恢复为Java对象的过程。
全栈程序员站长
2022/09/13
2.7K0
SpringBoot的序列化和反序列化
实现一个JSON解析器,有那么难吗?
JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)。这些特性使JSON成为理想的数据交换语言。
Java团长
2019/03/06
1.3K0
实现一个JSON解析器,有那么难吗?
撸一个 JSON 解析器
JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)。这些特性使JSON成为理想的数据交换语言。
芋道源码
2019/05/13
1K0
相关推荐
从Gson 的一个著名Bug说起
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档