HOWTO · Java

在 Java 中將字串轉換為 JSON 物件

本教程介紹瞭如何在 Java 中把一個字串轉換成一個 json 物件。

本頁內容

要在 Java 中使用 JSON 文字,請使用 JSON 函式庫對其進行解析。解析會產生一個特定於函式庫的 JSON 樹,你可以動態地檢查它;而將文字對映到 Java 類別則會產生一個類型化物件。這裡的三個選項是 org.json、Gson 和 Jackson。每個選項都需要其自己的相依性。當你想動態檢查欄位時選擇樹,或者當資料形狀已知且類型化欄位有用時對映到 Java 類別。

在 Java 中使用 JSONObject 把一個字串轉換為 JSON 物件

JSON-java 函式庫(org.json)使用 new JSONObject(json) 解析物件字串。對於 Maven,請在 pom.xml 的 <dependencies> 元素內新增 org.json:json:20201115。該建構函式傳回一個 JSONObject;使用 getString("name") 和 getInt("age") 讀取字串成員和整數成員。這些呼叫傳回 Java 值,而 JSONObject 仍然是該函式庫的記憶體中 JSON 物件表示形式。按鍵檢索成員,因為物件成員順序不是可靠的語義屬性。

下面的完整範例使用 new JSONObject(json) 解析共享樣本 {"name":"John","age":30},讀取並列印兩個欄位,並處理 JSONException:

import org.json.JSONException;
import org.json.JSONObject;

public class StringToJsonObjectWithJsonOrg {
    public static void main(String[] args) {
        String json = "{\"name\":\"John\",\"age\":30}";
        try {
            JSONObject object = new JSONObject(json);
            System.out.println("name: " + object.getString("name"));
            System.out.println("age: " + object.getInt("age"));
        } catch (JSONException e) {
            System.err.println("Invalid JSON: " + e.getMessage());
        }
    }
}
name: John
age: 30

作為比較,下面的僅使用 JDK 的範例同樣擷取樣本中的兩個欄位並列印它們的值,它只使用一個正規表示式。它僅限於這種扁平的輸入形狀;它不會解析或驗證一般 JSON。輸入是在 main 中宣告的,因此請將程式碼片段儲存為 StringToJsonObject.java,並使用 JDK 編譯它。

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class StringToJsonObject {
    public static void main(String[] args) {
        String json = "{\"name\":\"John\",\"age\":30}";
        Pattern field = Pattern.compile("\\\"(name|age)\\\"\\s*:\\s*(?:\\\"([^\\\"]*)\\\"|(\\d+))");
        Matcher matcher = field.matcher(json);
        Map<String, String> values = new LinkedHashMap<>();
        while (matcher.find()) {
            String value = matcher.group(2) != null ? matcher.group(2) : matcher.group(3);
            values.put(matcher.group(1), value);
        }
        System.out.println("name: " + values.get("name"));
        System.out.println("age: " + values.get("age"));
    }
}
name: John
age: 30

這個正規表示式僅涵蓋所顯示的字串成員和整數成員。它不會驗證 JSON 語法,也不能正確處理逸出引號、巢狀結構、陣列或其他 JSON 值。對於應用程式輸入,請使用 JSONObject 或其他解析器,並在讀取所需成員之前檢查它們是否存在並具有預期的類型。在解析和類型化讀取周圍捕獲 JSONException,以便呼叫方可以報告解析或值存取失敗,或從中復原。

使用 Google Gson 在 Java 中將字串轉換為 JSON 物件

Gson 可以將文字解析為 JSON 樹,或將其直接對映到 Java 類別。要在不定義類別的情況下檢查欄位,請在 Maven 的 <dependencies> 元素內新增 com.google.code.gson:gson:2.8.6。使用 JsonParser.parseString(json).getAsJsonObject() 解析樹,然後使用 object.get("name").getAsString() 和 object.get("age").getAsInt() 讀取成員。這將傳回一個 JsonObject 樹,而不是網域類別的實例。

下面的完整範例將同一樣本解析為 JsonObject,讀取並列印兩個欄位,並處理解析錯誤:

import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;

public class StringToJsonObjectWithGson {
    public static void main(String[] args) {
        String json = "{\"name\":\"John\",\"age\":30}";
        try {
            JsonObject object = JsonParser.parseString(json).getAsJsonObject();
            System.out.println("name: " + object.get("name").getAsString());
            System.out.println("age: " + object.get("age").getAsInt());
        } catch (JsonParseException | IllegalStateException e) {
            System.err.println("Invalid JSON: " + e.getMessage());
        }
    }
}
name: John
age: 30

如果資料具有已知的形狀並且類型化欄位有用,請定義一個具有 String name 欄位和 int age 欄位的 User 類別,然後呼叫 new Gson().fromJson(json, User.class) 以產生一個 User。要將該實例重新序列化為 JSON 文字,請呼叫 new Gson().toJson(user)。GsonBuilder.setPrettyPrinting() 在序列化期間設定格式;它不會改變解析後的樹或 Java 值。處理解析問題時請處理 JsonParseException,然後驗證必填欄位,因為有效的 JSON 仍可能省略你的程式需要的資料。

使用 Jackson 將字串轉換為 JSON 物件

當你需要動態選擇欄位時,Jackson 的樹模型很有用。在 Maven 的 <dependencies> 元素內新增 com.fasterxml.jackson.core:jackson-databind:2.11.3。jackson-databind 工件提供 ObjectMapper 樹 API,並將 Jackson core 作為相依性引入。呼叫 new ObjectMapper().readTree(json) 將文字解析為 JsonNode,即 Jackson 的 JSON 樹表示形式。使用 node.get("name").asText() 和 node.get("age").asInt() 讀取樣本值;對每個值使用相符的成員。

下面的完整範例使用 ObjectMapper.readTree(json),讀取並列印兩個欄位,並處理受檢查例外 JsonProcessingException:

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public class StringToJsonObjectWithJackson {
    public static void main(String[] args) {
        String json = "{\"name\":\"John\",\"age\":30}";
        try {
            JsonNode node = new ObjectMapper().readTree(json);
            System.out.println("name: " + node.get("name").asText());
            System.out.println("age: " + node.get("age").asInt());
        } catch (JsonProcessingException e) {
            System.err.println("Invalid JSON: " + e.getMessage());
        }
    }
}
name: John
age: 30

readTree 可以引發受檢查例外 JsonProcessingException,因此請在進行解析的地方處理它。此外,在使用 asText() 或 asInt() 等方便的存取器之前,請檢查每個請求的節點是否存在並具有預期的類型。否則,即使 JSON 文件本身已成功解析,缺失或類型不同的成員也可能產生不適合應用程式的值。

這三個函式庫都解析 JSON 文字,但它們的樹類型和 API 各不相同:JSONObject、JsonObject 和 JsonNode。格式錯誤的文件會在解析期間失敗,例外類別和訊息取決於所選的函式庫。僅靠解析並不能確保必填欄位存在,也不能確保值具有你的應用程式預期的類型,因此請在使用前驗證它們。僅使用 JDK 的正規表示式範例僅限於所顯示的扁平樣本;對於一般 JSON 輸入,請使用有相依性支援的函式庫 API 之一。