转 https://www.jianshu.com/p/75a50aa0cad1

GSON弥补了JSON的许多不足的地方,在实际应用中更加适用于Java开发。在这里,我们主要讲解的是利用GSON来操作java对象和json数据之间的相互转换,包括了常见的对象序列化和反序列化的知识。

一、前言

因为json有2种类型:

  • 一种是对象,object -> {key:value,key:value,...}
  • 另一种是数组,array -> [value,value,...]

所以针对这两种类型,来展开对json数据的操作。

GSON在解析json的时候,大体上有2种类型,一种是直接在内存中生成object或array,通过手工指定key来获取值;另一种是借助javabean来进行映射获取值。

二、对 json 数据进行反序列化,得到java 对象

1、不借助java 类,直接解析json 数据

1、json 是对象类型

当ajax传过来的json数据属于对象时,不论这个对象简单还是复杂,都可以轻松地把它们给解析出来。

ajax传过来的json数据(是对象形式):

var data_json =  {
"sex": '男',
"hobby":["baskte","tennis"],
"introduce": {
"name":"tom",
"age":23
}
}; data: JSON.stringify(data_json),

GSON解析:

BufferedReader reader = request.getReader();
// 读取json数据
StringBuffer buffer = new StringBuffer();
String s;
while ((s = reader.readLine()) != null) {
buffer.append(s);
}
String json = buffer.toString();
System.out.println("json:" + json); // json解析器,解析json数据
JsonParser parser = new JsonParser();
JsonElement element = parser.parse(json);
// json属于对象类型时
if (element.isJsonObject()) {
JsonObject object = element.getAsJsonObject(); // 转化为对象 // 1. value为string时,取出string
String sex = object.get("sex").getAsString(); System.out.println("sex:" + sex); // 2. value为array时,取出array
JsonArray hobbies = object.getAsJsonArray("hobby"); //
for (int i = 0; i < hobbies.size(); i++) {
String hobby = hobbies.get(i).getAsString();
System.out.println("hobby:" + hobby);
} // 3. value为object时,取出object
JsonObject introduce = object.getAsJsonObject("introduce");
String name = introduce.get("name").getAsString();
int age = introduce.get("age").getAsInt();
System.out.println("name:" + name+";age:" + age);
}

解读:

很明显,对于传过来的对象类型的json数据,使用GSON是很方便进行解析的,在得到了json数据对应的JsonObject 对象之后,我们就可以很简单地进行操作了。这种方法是直接获取json中的值,而没有进行java对象的还原(简单情况下,没有必要生成相应的javabean)。

2、json 是数组类型

ajax传过来的json数据(是数组形式):

var data_json =  [
"cake",
2,
{"brother":"tom","sister":"lucy"},
["red","orange"]
]; data: JSON.stringify(data_json),

GSON解析:

BufferedReader reader = request.getReader();
StringBuffer buffer = new StringBuffer();
String s;
while ((s = reader.readLine()) != null) {
buffer.append(s);
}
String json = buffer.toString();
System.out.println("json:"+json); // json解析器,解析json数据
JsonParser parser = new JsonParser();
JsonElement element = parser.parse(json);
// json属于数组类型
if (element.isJsonArray()) {
JsonArray array = element.getAsJsonArray(); // 1. value为string时,取出string
String array_1 = array.get(0).getAsString();
System.out.println("array_1:"+array_1); // 2. value为int时,取出int
int array_2 = array.get(1).getAsInt();
System.out.println("array_2:"+array_2); // 3. value为object时,取出object
JsonObject array_3 = array.get(2).getAsJsonObject();
String brother = array_3.get("brother").getAsString();
String sister = array_3.get("sister").getAsString();
System.out.println("brother:"+brother+";sister:"+sister); // 4. value为array时,取出array
JsonArray array_4 = array.get(3).getAsJsonArray();
for (int i = 0; i < array_4.size(); i++) {
System.out.println(array_4.get(i).getAsString());
} }

解读:

当json是数组类型的时候,使用GSON操作和上一小节几乎差不多,只不过是第一步生成的json对象是数组而已。上面2种方式解析json十分简单,在日常使用中足够了。

但是对于有规律的json数据,比如往往是可以映射成一个javabean对象,那么我们就没有必要一个个手工取值了,我们可以借助javabean配合GSON来更加快速地解析json数据。

2、借助java 类,生成对应java 对象来解析数据

详细的前端json 数据,可以看前面的反例,以下只是使用直接的json数据进行说明。

生成对于的java对象之后,就可以通过getter方法来获取相应的数据了。

通用代码:

在这个方法里,借助json数据来生成java对象的代码都是一致的:

Gson gson = new Gson();
BeanType bean = gson.fronJson(jsonData, BeanType.class);

1. json 是对象类型

1.1 基本案列

json 数据

{"name":"tom","salary":2999}

java类

public class MyEntry {
private String name;
private int age;
public String address;
public int salary;
// getter、setter、toString
}

java 代码

String json1 = "{\"name\":\"tom\",\"salary\":2999}";
Gson gson1 = new Gson();
MyEntry entry1 = gson1.fromJson(json1, MyEntry.class);
System.out.println(entry1.toString()); // name:tom,age:0,address:null,salary:2999

解读

可以看出,对于不完整的json 数据,在我们映射了相应的java 类之后,转化得到的java对象,未赋值的字段都是默认值。这就符合java的规范和常理。

1.2 字段名并不一致怎么办?

如果前端传过来的json 数据的key和我们java类的字段不一致,就需要我们在java类中手工进行指定。

@SerializedName() 注解

比如对于上面的json 数据,salary 改成money ,我们得到的java对象中,salary 就会变成默认值:0。

因此,我们要使用注解:

@SerializedName("money")
private String salary; @SerializedName({"money", "salary"}) // 可以有多个备选值
private String salary;
1.3 如何限定某个字段不参加序列化或反序列化?

@Expose()注解

如果想要让java类的某些字段不参加序列化或反序列化,可以显示来设置。如:

@Expose(serialize=false,deserialize=false)
private String name;

上面的name 字段将不参加序列化及反序列化。

1.4 复合的对象怎么处理?

json 数据是对象形式时,常见的value 会是一个数组或对象。如:

{
"name": "tom",
"age": 0,
"money": 2999,
"hobbies": [
"basket",
"tennis"
],
"collections": {
"2": "paint",
"3": "mouse"
}
}

举一反三,value 是数组时(hobbies),对应在java类中也是数组;value 是对象时,对应在java类中就是map(k-v对)了。

因此,我们可以很容易得到对应的java类:

private List<String> hobbies;
private Map<Integer, String> collections;

解读: 可知,再复杂的json 数据,我们也可以构造出对应的java类。

2. json 是数组类型

1.1 基本案例:

json数据

["apple", "banana", "pear"]

显然,数组在java中对应的也是数组。

java代码

String json2 = "[\"apple\", \"pear\", \"banana\"]";
Gson gson2 = new Gson();
// 传入的java类型是String[].class
String[] fruits = gson2.fromJson(json2, String[].class);
1.2 我想用List 数组

对于上面这种简单的数组形式的json数据,我们还可以反序列化为List类型的数组。因为List进行增删改都比较方便。

这里就要使用泛型了,具体的泛型讲解,会在下面进行说明。

String json2 = "[\"apple\", \"pear\", \"banana\"]";
Gson gson2 = new Gson();
List<String> fruitList = gson2.fromJson(json2, new TypeToken<List<String>>(){}.getType());

3、使用泛型

有的时候,传过来的json数据在格式上是很相近的,只不过某个字段的value不固定,如果为此生成多个相似的java类就十分多余了。

如:前端传过来的json数据主要是2类:

{"code":"0","message":"success","data":{}}
{"code":"0","message":"success","data":[]}

对于字段data ,有时候是对象,有时候是数组。

这里,我们将使用Result<T> 来映射json数据,使用MyEntry 类来映射json 数据的data 部分。这意味着,对于不同的json数据,我们将不再生成多个java类,而是动态生成所需的java对象。

result对象

public class Result<T>{
public int code;
public String message;
public T data;
// getter、setter
}
1.1 data为对象的json1:
{
"code": 0,
"message": "success",
"data": [
{
"name": "tom",
"age": 32,
"address": "street one",
"salary": 4999
},
{
"name": "tom",
"age": 32,
"address": "street one",
"salary": 4999
}
]
}

java代码

String typeJson1 = "{\n" +
" \"code\":0,\n" +
" \"message\":\"success\",\n" +
" \"data\":{\n" +
" \"name\":\"tom\",\n" +
" \"age\":32,\n" +
" \"address\":\"street one\",\n" +
" \"salary\":4999\n" +
" }\n" +
"}";
Gson typeGson1 = new Gson();
// 动态生成所需的java类的类型
Type type1 = new TypeToken<Result<MyEntry>>(){}.getType();
// 动态生成java对象
Result<MyEntry> result1 = typeGson1.fromJson(typeJson1, type1);
System.out.println(result1);
1.2 data为数值的json2:
{
"code": 0,
"message": "success",
"data": [
{
"name": "tom",
"age": 32,
"address": "street one",
"salary": 4999
},
{
"name": "lucy",
"age": 24,
"address": "street three",
"salary": 2333
}
]
}

java代码

String typeJson2 = "{\n" +
" \"code\": 0,\n" +
" \"message\": \"success\",\n" +
" \"data\": [\n" +
" {\n" +
" \"name\": \"tom\",\n" +
" \"age\": 32,\n" +
" \"address\": \"street one\",\n" +
" \"salary\": 4999\n" +
" },\n" +
" {\n" +
" \"name\": \"lucy\",\n" +
" \"age\": 24,\n" +
" \"address\": \"street three\",\n" +
" \"salary\": 2333\n" +
" }\n" +
" ]\n" +
"}";
Gson typeGson2 = new Gson();
// 再次动态生成java类型
Type type2 = new TypeToken<Result<List<MyEntry>>>(){}.getType();
// 再次动态生成java对象
Result<List<MyEntry>> result2 = typeGson2.fromJson(typeJson2, type2);
System.out.println(result2);

四、java 对象序列化为json 数据

这一部分,主要是讲解如何将一个java对象序列化为json数据,也会涉及到如何组装这个java对象。

1、由具体的java类对象,序列化为json 数据

我们可以直接把java对象给序列化为json数据。对于未设置的属性,会采取默认值;但是如果默认是null的话,该属性就不会被序列化。

java类,我们仍然采用的是MyEntry 类。

MyEntry entry2 = new MyEntry();
entry2.setName("tom");
entry2.setSalary(2999);
List<String> hobbies = new ArrayList<>();
hobbies.add("basket");
hobbies.add("tennis");
entry2.setHobbies(hobbies);
Map<Integer, String> collections = new HashMap<>();
collections.put(2, "paint");
collections.put(3, "mouse");
entry2.setCollections(collections);
Gson gson2 = new Gson();
String json2 = gson2.toJson(entry2);
System.out.println(json2);
// {"name":"tom","age":0,"money":2999,"hobbies":["basket","tennis"],"collections":{"2":"paint","3":"mouse"}}

对于非值属性,即引用属性,如hobbies、collections,如果没有设置值的话,在序列化后的json数据中,是不会出现的。而如果是值属性的话,没有设置值的情况下,在json数据中会是使用java中的默认值。

1.1 要生成对象形式的json 数据

  • 第一种方法是上面的,直接使用java类对象
  • 还可以使用生成map对象,进行序列化

1.2 要生成数组形式的json 数据

  • 第一种,使用String[] 字符串数组来生成
  • 还可以使用List对象来序列化
  • 还可以使用Set对象来序列化

对于序列化的要求,更多的情况会使用注解来选择需要/不需要进行序列化的字段。

作者:7叶
链接:https://www.jianshu.com/p/75a50aa0cad1
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

转 GSON的更多相关文章

  1. No-args constructor for class X does not exist. Register an InstanceCreator with Gson for this type to fix this problem.

    Gson解析JSON字符串时出现了下面的错误: No-args constructor for class X does not exist. Register an InstanceCreator ...

  2. Gson将字符串转换成JsonObject和JsonArray

    以下均利用Gson来处理: 1.将bean转换成Json字符串: public static String beanToJSONString(Object bean) { return new Gso ...

  3. Gson解析纯Json数组

    [ { "type": "123", "value": 123 }, { "type": "234" ...

  4. 【Gson】互相转化

    Gson 是 Google 提供的用来在 Java 对象和 JSON 数据之间进行映射的 Java 类库.可以将一个 JSON 字符串转成一个 Java 对象,或者反过来. 对象转为字符串 Strin ...

  5. Android Gson解析

    目前解析json有三种工具:org.json(Java常用的解析),fastjson(阿里巴巴工程师开发的),Gson(Google官网出的),解析速度最快的是Gson,下载地址:https://co ...

  6. Android总结之json解析(FastJson Gson 对比)

    前言: 最近为了统一项目中使用的框架,发现项目中用到了两种json解析框架,他们就是当今非常主流的json解析框架:google的Gson 和阿里巴巴的FastJson,为了废除其中一个所以来个性能和 ...

  7. gson笔记 解析json数据

    gson中负责json数据解析的类是JsonReader. Json格式有两种结构,一种是对象(键值对的组合,无序),另外一种是数组(值的有序集合). 因此针对这两种格式,JsonReader提供了不 ...

  8. Android Gson的使用总结

    1.概念 Gson是谷歌发布的一个json解析框架 2.如何获取 github:https://github.com/google/gson android studio使用 compile 'com ...

  9. Android JSON、GSON、FastJson的封装与解析

    声明: 1.本帖只提供代码,不深入讲解原理.如果读者想要深入了解,那就不要在这个帖子上浪费时间了 2.客户端用的是Google官方的Volley访问服务器,具体了解Volley请戳 这里 3.本帖三种 ...

  10. Java Gson 简要笔记

    Gson是Google开发的Java比较好用的 Json工具. 使用挺简单,假设有个类: class Runner { int attr; String name; public Runner(int ...

随机推荐

  1. AppScan 10安装使用

    一.简介 AppScan是IBM的一款web安全扫描工具,具有利用爬虫技术进行网站安全渗透测试的能力,能够根据网站入口自动摸取网页链接进行安全扫描,提供了扫描.报告和修复建议等功能. appscan有 ...

  2. Python之模块导入(不看会后悔系列)

    看到这个标题猜想大家内心OS: 什么辣鸡水文,划走划走~ 别急有干货! 静态导入(照顾新人) 假设现在有两个文件a,b在不同目录,b文件想引用a文件中的函数: # test_module/sub_mo ...

  3. Python打包成exe,文件太大问题解决办法

    Python打包成exe,文件太大问题解决办法 原因 解决办法 具体步骤 情况一:初次打包 情况二:再次打包 原因 由于使用pyinstaller打包.py文件时,会把很多已安装的无关库同时打包进去, ...

  4. hudi clustering 数据聚集(三 zorder使用)

    目前最新的 hudi 版本为 0.9,暂时还不支持 zorder 功能,但 master 分支已经合入了(RFC-28),所以可以自己编译 master 分支,提前体验下 zorder 效果. 环境 ...

  5. CCCC-exercise

    CCCC-exercise 1.L1 总结L1 1-27里面我觉得有东西可以总结的题目 贴了部分的代码 L1-006(20) 一个正整数 N 的因子中可能存在若干连续的数字.例如 630 可以分解为 ...

  6. 详解电子表格中的json数据:序列化与反序列化

    从XML到JSON 当下应用开发常见的B/S架构之下,我们会遇到很多需要进行前后端数据传输的场景.而在这个传输的过程中,数据通过何种格式传输.方式是否迅速便捷.书写方式是否简单易学,都成为了程序员在开 ...

  7. 菜鸡的Java笔记 - java 断言

    断言:assert (了解)        所谓的断言指的是在程序编写的过程之中,确定代码执行到某行之后数据一定是某个期待的内容        范例:观察断言 public class Abnorma ...

  8. GDI绘制Winform工作流组件、具有独立图层的增删处理、防PPT效果

    最近接了个小项目10K.用了2个下班时间写完,共花费了6-7个小时完成.如有同类需求的可以与本人联系,QQ:120772981 功能目标: 需要写一个仿PPT画泳道图的组件.之前写过工作流的组件,其实 ...

  9. PAT A1091——BFS

    Acute Stroke One important factor to identify acute stroke (急性脑卒中) is the volume of the stroke core. ...

  10. [loj3527]地牢游戏

    当英雄能力值$\ge 10^{7}$时,即能战胜所有敌人,简单预处理即可 若英雄能力值在$[2^{k},2^{k+1})$中,对敌人分类讨论: 1.若$s_{i}\le 2^{k}$,其必然会战胜这些 ...