Gson - Arrays 和 Lists 对象映射

原文链接: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<RestaurantMenuItem> 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<RestaurantMenuItem> 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<RestaurantMenuItem> 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 如下:

founderArray

Lists

实际开发中,我们更多的是转成一个 ArrayList,但是,我们不能像解析数组那样传入 List,为了让Gson知道我们要解析的数据类型,我们必须传递给它一个Type,内部根据 TypeToken 来区分要解析的类型。例如:

Type founderListType = new TypeToken<ArrayList<Founder>>(){}.getType();

完成解析如下:

String founderJson = "[{'name': 'Christian','flowerCount': 1}, {'name': 'Marcus', 'flowerCount': 3}, {'name': 'Norman', 'flowerCount': 2}]";

Gson gson = new Gson();

Type founderListType = new TypeToken<ArrayList<Founder>>(){}.getType();

List<Founder> founderList = gson.fromJson(founderJson, founderListType);

Debug如下:

founderList

以上两种方式,根据自己实际需求选择。接下来来看看反序列化操作。

### 列表作为对象的一部分

我们现在有一个这样的数据:

   {
    "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<Founder> 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如下:

GeneralInfo

除了解析成一个 List,也可以解析为数组格式。

List 中嵌套 List

Gson 也可以解析 List 中嵌套 List 数据结构,看下面这个例子,例如:

public class GeneralInfo {
    String name;
    String website;
    List<FounderWithPets> founders;
}

public class FounderWithPets {
    String name;
    int flowerCount;
    List<Pet> pets;
}

public class Pet {
    String name;
    List<Toy> 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 - 如何解析多态对象

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值