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 - 如何解析多態對象

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章