GSON

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對象來序列化

對于序列化的要求,更多的情況會使用注解來選擇需要/不需要進行序列化的字段。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,119評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,382評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,038評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,853評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,616評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,112評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,192評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,355評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,869評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,727評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,928評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,467評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,165評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,570評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,813評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,585評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,892評論 2 372

推薦閱讀更多精彩內容

  • 1.概述2.Gson的目標3.Gson的性能和擴展性4.Gson的使用者5.如何使用Gson 通過Maven來使用...
    人失格閱讀 14,303評論 2 18
  • 為了更好的學習Gson,特將Gson User Guide翻譯如下。由于本人英文水平有限,如有錯誤,還請指正,謝謝...
    WeberLisper閱讀 6,876評論 0 6
  • 2017年10月27日,如是家人蔡小敏,種種子第65天。 發心:我今天不僅是為了我個人而聞思修,更是為了六道回一切...
    Rubywry閱讀 188評論 0 1
  • 1. 叫做傅園慧的姑娘一下子迷倒了一片人,微博上表白的粉絲們連起來估計也能繞地球兩圈,“我已經用盡洪荒之力”的表情...
    Melonmelonmelon閱讀 2,138評論 7 50
  • 跨年是有神奇能量的嗎?入8以來對我來說一切都變了…… 1號:和姐妹淘跑常熟買衣服,淘到一套套裙(柔美之致),這...
    行走的蜜糖閱讀 324評論 1 4