Java Json API:Gson使用簡單入門

ImportNew發表於2015-09-09

GSON是Google開發的Java API,用於轉換Java物件和Json物件。本文討論並提供了使用API的簡單程式碼示例。更多關於GSON的API可以訪問:http://sites.google.com/site/gson/.

完全理解Gson(1):簡單入門

本文是GSON系列文章的第一篇。本文是其他文章的基礎,因此不需要任何GSON或JSON經驗。第二篇文章提供了關於GSON反序列化(從JSON到Java)的示例,第三篇文章提供了關於GSON序列化(從Java到JSON)的示例。

下面列出的所有程式碼都可以在https://java-creed-examples.googlecode.com/svn/gson/Simple%20Gson%20Example. 找到。絕大部分示例都不會包含全部的程式碼,可能會忽略一些片段,這些片段都與討論的示例無關。讀者可以從上面的連結下載或查閱所有程式碼。

讀者需要有基礎的Java(教程)知識和很基礎的Maven(首頁)知識。這裡展示的程式碼使用maven來下載GSON庫。把專案匯入到Springsource Tool Suite(推薦的IDE),無需任何配置。

下載與安裝

在使用GSON API工作之前,你需要下載庫(jar檔案),並將其包含到類路徑中。庫,連同原始碼和Java文件,都可以從http://code.google.com/p/google-gson/downloads/list下載。下載完畢後,新增gson-<version>.jar到類路徑。對於那些偏好使用Maven管理依賴(JAR檔案)的讀者,新增如下依賴到pom.xml。

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.2.4</version>
</dependency>

需要修改 <version>2.2.4</version>。本文所有程式碼示例使用上面列出的版本。pom.xml檔案拷貝可以在這裡找到。

如果這個庫用於web應用,請確保在WEB-INF/lib資料夾中保持一份拷貝。或者,GSON庫可以放到應用伺服器提供給web應用。

一個簡單示例

GSON API提供一個類檔案,Gson(Java文件),它被用來處理Java和JSON物件的轉換。可以呼叫預設構造器,或如下程式碼的形式,使用GsonBuilder(Java文件)類建立這個類的例項。GsonBuilder類是可定製化的,並且允許開發者按需例項化Gson。

package com.javacreed.examples.gson.part1;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class SimpleExample1 {
    public static void main(String[] args) {
        Gson gson = new GsonBuilder().create();
        gson.toJson("Hello", System.out);
        gson.toJson(123, System.out);
    }
}

在上面的例子中,我們建立了一個Gson例項,並把Java String和int轉化為JSON物件。以上程式碼命令列裡的輸出結果如下:

"Hello"123

這不是火箭科學,但它是一個開始。注意,上述的結果都將輸入到命令列。該toJason()方法有兩個引數,Java物件轉換為JSON和可追加(Java的文件)的一個例項。我們可以很容易地改變了一個檔案或網路流。

package com.javacreed.examples.gson.part1;

import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class SimpleExample2 {
    public static void main(String[] args) throws IOException {
        Writer writer = new FileWriter("Output.json");

        Gson gson = new GsonBuilder().create();
        gson.toJson("Hello", writer);
        gson.toJson(123, writer);

        writer.close();
    }
}

注意

為什麼變數宣告為Writer型別,而實際型別是FileWriter?

儘量使用泛型是一個很好的方法。在上例中,我們只使用了Appendable和Writer介面定義的方法。使用泛型使程式碼更易於移植和維護,下面是個不好的例子。

注意,上面例子中,我們沒有正確處理流(Writer)。理想情況下,資源在finaly塊 (教程) 中關閉或者用在try-with-resource(教程)中。我們忽略了這個是為了保持程式碼簡潔。

public static void main(String[] args) throws IOException {
    try (Writer writer = new FileWriter("Output.json")) {
        Gson gson = new GsonBuilder().create();
        gson.toJson("Hello", writer);
        gson.toJson(123, writer);
    }
}

以上程式碼生成檔案:包含JSON物件的Output.json。注意,這裡我們使用了字元流而不是位元組流。因為toJson()方法需要一個Appendanble例項,而位元組流不能實現Appendable介面,所以我們使用了字元流。Appendable介面處理字元而不是位元組。Java提供了InputStreanReader(Java文件)和OutputStreamWriter(Java文件)類進行位元組流與字元流的轉換,如下面的例子。

注意

注意,使用InputStreamREader和OutputStreamWriter類時,如果不提供編碼或者字符集,轉換將使用平臺預設字符集。這將降低程式碼的可移植性,且在其他平臺上執行將可能產生錯誤行為。

package com.javacreed.examples.gson.part1;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class SimpleExample3 {

    public static void main(String[] args) throws IOException {
        try(Writer writer = new OutputStreamWriter(new FileOutputStream("Output.json") , "UTF-8")){
            Gson gson = new GsonBuilder().create();
            gson.toJson("Hello", writer);
            gson.toJson(123, writer);
        }
    }
}

如你所見,我們只需要改變例項的一部分。程式碼的剩餘部分沒有任何變化。這就是使用介面代替類作為變數型別的好處之一。

使用JSON物件

比方說,我們需要使用JSON物件並載入他們為Java物件。假設web伺服器查詢時產生如下JSON物件:

{
  NAME:"Albert Attard",
  P_LANGUAGE:"Java",
  LOCATION:"Malta"
}

此JSON物件包含3個不同值的域。比如我們需要使用JSON物件並建立一個Java物件來展示它。為了使這個例子更有趣,假設我們只關心name和location域。

首先建立一個Java類來表示name和location。類命名為Person。類的名字無關緊要,但域的名字必須一致。域名必須匹配(大小寫敏感)JSON物件中的名字。更進一步,類必須包含一個預設建構函式(即使它被設定為private)。如下所示,name和location域在JSON中是大寫的。JSON中域P_LANGUAGE被忽略了,因為Java物件中不包括該名稱的域。請理解域名不遵守Java命名規範,暫時只是為了簡化。更多內容將在第2部分中討論。

package com.javacreed.examples.gson.part2;

public class Person {
    private String NAME;
    private String LOCATION;

    // Getters and setters are not required for this example.
    // GSON sets the fields directly using reflection.

    @Override
    public String toString() {
        return NAME + " - " + LOCATION;
    }
}

準備好Java物件後,我們可以讀取JSON物件並載入為Java物件,如下程式碼所示。為了模擬真實情況,我們使用了位元組流作為輸入。還要注意,JSON內容儲存在resource資料夾的檔案裡(這不是常規做法)。

package com.javacreed.examples.gson.part2;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class JsonToJava {

    public static void main(String[] args) throws IOException {
        try(Reader reader = new InputStreamReader(JsonToJava.class.getResourceAsStream("/Server1.json"), "UTF-8")){
            Gson gson = new GsonBuilder().create();
            Person p = gson.fromJson(reader, Person.class);
            System.out.println(p);
        }
    }
}

輸出如下:

Albert Attard - Malta

Gson解析JSON物件並建立了一個Person類的例項,並列印到命令列中。

巢狀JSON物件

讓我們對上面的例子更進一步,以下所示JSON程式碼段包含了一個巢狀物件。

{
  NAME:"Albert Attard",
  P_LANGUAGE:"Java",
  LOCATION:"Malta",
  EXAM: {
    SUBJECT:"Programming",
    GRADE:4.5
  }
}

EXAM域由兩個域組成,分別是SUBJECT和GRADE。我們需要修改Person類的定義來包含EXAM域,並建立一個新的Java類來表示EXAM,該類包含SUBJECT和GRADE域。

我們首先建立新的類來表示巢狀物件。就像之前討論那樣,類名無關緊要,但是域名必須與JSON中的域名匹配。

package com.javacreed.examples.gson.part3;

public class Exam {
    private String SUBJECT;
    private double GRADE;

    // Getters and setters are not required for this example.
    // GSON sets the fields directly using reflection.

    @Override
    public String toString() {
        return SUBJECT + " - " + GRADE;
    }
}

現在我們可以修改Person類,引入一個與JSON中EXAM同名的域,型別為Exam。注意,下面的Person類與前一個<span style=”color: #ff0000;”>位於</span>不同的包。

package com.javacreed.examples.gson.part3;

public class Person {

    private String NAME;
    private String LOCATION;
    private Exam EXAM;

    @Override
    public String toString() {
        return NAME + " - " + LOCATION + " (" + EXAM + ")";
    }
}

注意,所需的變化是最小的,因為Gson動態發現(使用反射)類和它的域。本文不包含反射,對於更多關於反射的資訊,請參考:Reflection in Action.

最後,讓我們嘗試新的變化。

package com.javacreed.examples.gson.part3;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class JsonToJava {

    public static void main(String[] args) throws IOException {
        try(Reader reader = new InputStreamReader(JsonToJava.class.getResourceAsStream("/Server2.json"), "UTF-8")){
            Gson gson = new GsonBuilder().create();
            Person p = gson.fromJson(reader, Person.class);
            System.out.println(p);
        }
    }
}

JsonToJava類沒有做任何改變,因為Gson使用了模型(Person和Exam類)將Json對映成Java。

結論

即使JSON可能是一個新概念,但它十分簡單與直接。此外,相比於需要增加標籤進行訊息/資料轉換而不斷膨脹的笨重的XML,它因為簡單更加流行。需要指出JSON是JavaScript的一個子集,JavaScript將它作為一個完美的方案來進行資料交換,例如網頁。GSON API使它更便於使用,即使在這裡沒有討論的部分,它也提供了強大的靈活性。

欲瞭解更多GSON的例子,請移步第2部分,我們會探索更復雜的例子,並討論如何使用GSON解串器來完全控制反序列化過程。

相關文章