原文链接:Gson — Mapping of Arrays and Lists of Objects
原文出自:Norman Peitek
译者:無名
欢迎来到我们的 Gson 系列的另一篇文章,在回顾了 Gson 的基础用法之后,例如:模型注解和嵌套对象的映射,我们来讨论本文重点功能:数组和列表对象的映射,我们几乎都会使用到这种数据类型,幸运的是 Gson 可以帮我们轻松搞定。
Array 和 List 差异
在我们介绍序列化之前,我们先来看下 Java 中的两种数据结构:Array 和 List。在 Java 中两者实现方式不同,使用哪一种数据类型取决于你的实际需求,但是在序列化这个问题上,Gson 并不关心这两种数据结构的具体实现。
在 JSON 数据格式中,不存在数组等结构,只是 Java 的具体实现使得这两种数据类型有很大不同。但是在上层它们表示出相同的结构,接下来,我们将重新理解这两种数据类型,在看过几个例子之后你就懂了。
Array 和 List 序列化
还记得上一篇关于 restaurant model 的嵌套对象吗?接下来,我们为restaurant 添加一个 menu 属性,包含两个字段,restaurant 中的菜单可以理解成一个 restaurant 列表。如下:
提示:我们这里只是简单的举个菜单的例子,这个数据结构不是一个完整的数据,所以它是不能被真实使用的。
首先要创建一个 Java model 类:
public class RestaurantWithMenu {
String name;
List menu;
//RestaurantMenuItem[] menu; // alternative, either one is fine
}
public class RestaurantMenuItem {
String description;
float price;
}
通过嵌套对象的方式即可,在 Java Model 中包含要映射变量的引用就可以了,要注意名字和JSON中字段名相同。
JSON 格式如下:
{
"name": "Future Studio Steak House",
"menu": [
...
]
}
与嵌套对象类似,我们没有 menu 的直接值,相反,JSON 中通过 "[]" 来包含一个对象,如上所述,在 JSON 数据中,数组和 List 结构是没有区别的。
menu 中包含一些对象,在我们那的 model 中,menu 只是其中的一个变量,我们先来手动生成一个完整的 JSON 数据。
通过下面这种方式,我们来模拟一个完整的 restaurant 数据:
List menu = new ArrayList<>();
menu.add(new RestaurantMenuItem("Spaghetti", 7.99f));
menu.add(new RestaurantMenuItem("Steak", 12.99f));
menu.add(new RestaurantMenuItem("Salad", 5.99f));
RestaurantWithMenu restaurant = new RestaurantWithMenu("Future Studio Steak House", menu);
Gson gson = new Gson();
String restaurantJson = gson.toJson(restaurant);
生成 JSON 如下:
{
"menu": [
{
"description": "Spaghetti",
"price": 7.99
},
{
"description": "Steak",
"price": 12.99
},
{
"description": "Salad",
"price": 5.99
}
],
"name": "Future Studio Steak House"
}
如我们预料,我们得到了想要的数据,按照字母顺序,menu 排在了name 的前面,根据 "[]" 标志 List 开始,根据 "{}" 标志对象开始。
但是我们并不是总是将 List 嵌套在对象中,我们可能会直接得到一个 List,Gson 也是支持直接序列化一个 List。
List menu = new ArrayList<>();
menu.add(new RestaurantMenuItem("Spaghetti", 7.99f));
menu.add(new RestaurantMenuItem("Steak", 12.99f));
menu.add(new RestaurantMenuItem("Salad", 5.99f));
Gson gson = new Gson();
String menuJson = gson.toJson(menu);
输出:
[
{
"description": "Spaghetti",
"price": 7.99
},
{
"description": "Steak",
"price": 12.99
},
{
"description": "Salad",
"price": 5.99
}
]
来看下数据中的不同,JSON 中的 "[" 表示一个对象列表开始,"{" 表示一个对象开始了,我们应该记住 JSON 数据中格式差别。
数组和 List 反序列化
在第二部分我们将学习反序列化,我们将使用 Gson 来解析列表数据,在之前的例子中,我们列举了两种情况,一是列表作为跟节点,二是列表最为一个嵌套对象。
List 作为跟节点
来看一个列表最为根节点的例子:
[
{
"name": "Christian",
"flowerCount": 1
},
{
"name": "Marcus",
"flowerCount": 3
},
{
"name": "Norman",
"flowerCount": 2
}
]
根据之前介绍的,"[]"标示一个GSON 解析列表的开始和结束,我们还需要一个具体的 Java model类:
public class Founder {
String name;
int flowerCount;
}
接下来,我们将数据解析成我们想要的数据类型。
数组:
首先看解析成数组,通过 Gson 的 gson.fromJson 方法,我们很简单的将 GSON 解析成数组,注意这里传递的参数是 Founder[].class 而不是Founder.class ,如下:
String founderJson = "[{'name': 'Christian','flowerCount': 1}, {'name': 'Marcus', 'flowerCount': 3}, {'name': 'Norman', 'flowerCount': 2}]";
Gson gson = new Gson();
Founder[] founderArray = gson.fromJson(founderJson, Founder[].class);
Debug 如下:
Lists
实际开发中,我们更多的是转成一个 ArrayList,但是,我们不能像解析数组那样传入 List
Type founderListType = new TypeToken>(){}.getType();
完成解析如下:
String founderJson = "[{'name': 'Christian','flowerCount': 1}, {'name': 'Marcus', 'flowerCount': 3}, {'name': 'Norman', 'flowerCount': 2}]";
Gson gson = new Gson();
Type founderListType = new TypeToken>(){}.getType();
List founderList = gson.fromJson(founderJson, founderListType);
Debug 如下:
以上两种方式,根据自己实际需求选择。接下来来看看反序列化操作。
列表作为对象的一部分
我们现在有一个这样的数据:
{
"name": "Future Studio Dev Team",
"website": "https://futurestud.io",
"founders": [{
"name": "Christian",
"flowerCount": 1
}, {
"name": "Marcus",
"flowerCount": 3
}, {
"name": "Norman",
"flowerCount": 2
}]
}
老样子我们需要创建一个用来对应的 Java Model 类:
public class GeneralInfo {
String name;
String website;
List founders;
}
列表存在 Model 类中的一个好处就是,我们在使用Gson解析时不再需要传递 TypeToken,直接穿入类即可。
String generalInfoJson = "{'name': 'Future Studio Dev Team', 'website': 'https://futurestud.io', 'founders': [{'name': 'Christian', 'flowerCount': 1 }, {'name': 'Marcus','flowerCount': 3 }, {'name': 'Norman','flowerCount': 2 }]}";
Gson gson = new Gson();
GeneralInfo generalInfoObject = gson.fromJson(generalInfoJson, GeneralInfo.class);
Debug如下:
除了解析成一个 List,也可以解析为数组格式。
List 中嵌套 List
Gson 也可以解析 List 中嵌套 List 数据结构,看下面这个例子,例如:
public class GeneralInfo {
String name;
String website;
List founders;
}
public class FounderWithPets {
String name;
int flowerCount;
List pets;
}
public class Pet {
String name;
List toys;
}
JSON 中包含了三个 List,这里就不操作了,相信 Gson 也是可以解析的。只要我们将需要解析的类型传递正确就可以。
目标
本文你将了解如何使用Gson 来序列化和反序列化 ArrayList 和 数组,知道了如何根据 JSON 格式中的不同来判断是对象还是一个对象集合。
你可以通过评论或twitter @futurestud_io 反馈你的问题。
练习代码已上传 Github https://github.com/whiskeyfei/Gson-Review 可自行查看。
Gson 系列文章翻译回顾
1、Gson - Java-JSON 序列化和反序列化入门
2、Gson - 映射嵌套对象
3、Gson - Arrays 和 Lists 映射对象
4、Gson - Map 结构映射
5、Gson - Set 集合映射
6、Gson - 空值映射
7、Gson Model Annotations - 如何使用 @SerializedName 更改字段的命名
8、Gson Model Annotations - @SerializedName 匹配多个反序列化名称
9、Gson Builder - 基础和命名规则
10、Gson Builder - 序列化空值
11、Gson Builder - 忽略策略
12、Gson Builder - Gson Lenient 属性
13、Gson Builder - 特殊类型 Floats & Doubles
17、Gson Builder - 如何使用 @Expose 忽略字段
19、Gson Advanced - 映射枚举类型
20、Gson Advanced - 映射循环引用
21、Gson Advanced - 泛型
22、Gson Advanced - 简单自定义序列化 (Part 1)
24、Gson Advanced - 自定义反序列化基础
25、Gson Advanced - 自定义对象实例创建
26、Gson Advanced - 通过 @JsonAdapter 自定义(反)序列化过程
32、Practical Gson - 如何解析多态对象
更多内容可关注公众号查看