1. 概述
JSON(JavaScript Object Notation)是一種輕量級的數據交換格式,我們最常見地將其用於客户端與服務器之間的通信。 此外,它易於閲讀和編寫,並且與語言無關。一個 JSON 值可以是另一個 JSON 對象, 數組, 數字, 字符串, 布爾值(true/false)或 null。
在本教程中,我們將學習如何使用 Java 中可用的 JSON 處理庫(即 JSON-Java 庫,也稱為 org.json)創建、操作和解析 JSON。
2. 先決條件
首先,我們需要在我們的 pom.xml 中添加以下依賴項:
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20250517</version>
</dependency>我們可以從 Maven Central 倉庫 獲取最新版本。
但是,在使用 Android SDK 時,我們無需顯式包含依賴項,因為它已經包含了該包。
3. Java 中的 JSON [org.json包]
我們使用來自 JSON-Java 庫的類來在 Java 中解析和操作 JSON。我們還將其稱為 org.json。但是,我們不應將其與 Google 的 org.json.simple 庫混淆。
此外,該庫還可以將 JSON、XML、HTTP Headers、Cookies、逗號分隔列表或文本等相互轉換。
在本教程中,我們將查看以下類:
- JSONObject – 類似於 Java 的原生 Map 類型的對象,用於存儲無序的鍵值對
- JSONArray – 值的有序序列,類似於 Java 的原生 Vector 實現
- JSONTokener – 一種工具,用於將文本分解成一系列 tokens,這些 tokens 可供 JSONObject 或 JSONArray 使用以解析 JSON 字符串
- CDL – 一種工具,提供方法將逗號分隔的文本轉換為 JSONArray,反之亦然
- Cookie – 將 JSON String 轉換為 cookies,反之亦然
- HTTP – 用於將 JSON String 轉換為 HTTP headers,反之亦然
- JSONException – 此庫拋出的標準異常
4. JSONObject
JSONObject 是一種無序的鍵值對集合,類似於 Java 的原生 Map 實現。
- 鍵是唯一的 String,不能為 null。
- 值可以是布爾值、數字、字符串或 JSONArray 甚至 JSONObject.NULL 對象。
- JSONObject 可以用包含鍵和值,鍵值之間用冒號分隔,鍵值對之間用逗號分隔的字符串來表示。
- 它具有多個構造函數,用於創建 JSONObject。
它還支持以下主要方法:
- get(String key) – 獲取與提供的鍵關聯的對象,如果鍵不存在則拋出 JSONException
- opt(String key) – 獲取與提供的鍵關聯的對象,如果鍵不存在則返回 null
- put(String key, Object value) – 在當前 JSONObject 中插入或替換鍵值對
put() 方法是一個重載方法,接受 String 類型鍵和多種類型的值。
要查看 JSONObject 支持的完整方法列表,請訪問官方文檔:http://stleary.github.io/JSON-java/org/json/JSONObject.html
現在,讓我們討論一下此類的主要操作。
4.1. 直接從 JSONObject 創建 JSON
JSONObject 暴露了一個類似於 Java 中 Map 接口的 API。
我們可以使用 put() 方法並傳入鍵和值作為參數:
JSONObject jo = new JSONObject();
jo.put("name", "jon doe");
jo.put("age", "22");
jo.put("city", "chicago");現在我們的 JSONObject 將會呈現如下所示:
{"city":"chicago","name":"jon doe","age":"22"}JSONObject.put() 方法提供了七種不同的重載簽名。雖然鍵只能是唯一的、非空 String,但值可以是任何內容。
4.2. 從 Map 創建 JSON
與其直接將鍵值對放入 JSONObject 中,我們可以構建一個自定義的 Map,然後將其作為參數傳遞給 JSONObject 的構造函數。
以下示例將產生與上述相同的結果:
Map<String, String> map = new HashMap<>();
map.put("name", "jon doe");
map.put("age", "22");
map.put("city", "chicago");
JSONObject jo = new JSONObject(map);4.3. 從 JSON 字符串創建 JSONObject
要解析 JSON 字符串並將其轉換為 JSONObject,只需將 String 傳遞給構造函數。請務必轉義 JSON 字符串中的雙引號。
以下示例將產生與上述相同的結果:
JSONObject jo = new JSONObject(
"{\"city\":\"chicago\",\"name\":\"jon doe\",\"age\":\"22\"}"
);傳遞的 String 參數必須是一個有效的 JSON;否則,構造函數可能會拋出 JSONException。
4.4. 從 JSON 字符串解析 JSON 值
一旦我們從一個 JSONObject實例中構造出 String,就可以使用相應的 get方法來獲取每個屬性的值。
此外,我們可以為嵌套屬性創建 JSONObject,該屬性的值為 JSON。 我們可以重複執行此操作,以獲取嵌套的 JSON 值,只要需要。 讓我們通過一個示例進行演示:
@Test
void givenJSON_whenParsed_thenCorrectValueReturned() {
String jsonString = """
{
"type": "Feature",
"geometry": "Point",
"properties": {
"isValid": true,
"name": "Sample Point"
}
}
""";
JSONObject jsonObject = new JSONObject(jsonString);
String type = jsonObject.getString("type");
String geometry = jsonObject.getString("geometry");
JSONObject properties = jsonObject.getJSONObject("properties");
boolean isValid = properties.getBoolean("isValid");
assertEquals(type,"Feature");
assertEquals(geometry,"Point");
assertTrue(isValid);
}4.5. 將 Java 對象序列化為 JSON
JSONObject 的一個構造函數接受 POJO 作為參數。在下面的示例中,該包使用DemoBean 類中的 getter 方法,併為此創建適當的JSONObject。
要從 Java 對象獲取JSONObject,我們需要使用一個有效的 Java Bean 類:
DemoBean demo = new DemoBean();
demo.setId(1);
demo.setName("lorem ipsum");
demo.setActive(true);
JSONObject jo = new JSONObject(demo);以下是 JSONObject jo:
{
"name":"lorem ipsum",
"active":true,
"id":1
}雖然我們有將 Java 對象序列化為 JSON 字符串的方法,但此庫中沒有提供將 JSON 字符串反序列化為 Java 對象的方法。如果需要這種靈活性,我們可以切換到其他庫,例如 Jackson。
5. JSONArray
JSONArray 是一種有序的值集合,類似於 Java 的原生 Vector 實現:
- 值可以是 Number、String、Boolean、JSONArray 或 JSONObject,甚至可以是 JSONObject.NULL 對象
- 它以一個用方括號括起來的 String 表示,包含用逗號分隔的值集合
- 類似於 JSONObject,它具有一個接受源 String 並將其解析為 JSONArray 的構造函數
以下是 JSONArray 類的主要方法:
- get(int index) – 返回指定索引(介於 0 和總長度 - 1 之間)的值,否則拋出 JSONException
- opt(int index) – 返回與索引(介於 0 和總長度 - 1 之間)關聯的值。如果該索引處沒有值,則返回 null。
- put(Object value) – 將對象值追加到此 JSONArray 中。此方法是多餘的,並支持各種數據類型
要查看支持 JSONArray 的方法完整列表,請訪問官方文檔:http://stleary.github.io/JSON-java/org/json/JSONArray.html。
5.1. 創建 JSONArray
初始化 JSONArray 對象後,我們可以使用 put() 和 get() 方法來添加和檢索元素:
JSONArray ja = new JSONArray();
ja.put(Boolean.TRUE);
ja.put("lorem ipsum");
JSONObject jo = new JSONObject();
jo.put("name", "jon doe");
jo.put("age", "22");
jo.put("city", "chicago");
ja.put(jo);以下是我們 JSONArray (為了清晰起見,代碼已格式化)的內容:
[
true,
"lorem ipsum",
{
"city": "chicago",
"name": "jon doe",
"age": "22"
}
]5.2. 從 JSON 字符串直接創建 JSONArray
與 JSONObject 類似,JSONArray 也具有一個構造函數,它可以直接從 JSON String 創建 Java 對象:
JSONArray ja = new JSONArray("[true, \"lorem ipsum\", 215]");這個構造函數在源 String 無效的 JSON String 時可能會拋出 JSONException。
5.3. 直接從集合或數組創建 JSONArray
JSONArray 構造函數也支持將集合和數組對象作為參數傳遞。
我們只需將它們作為參數傳遞給構造函數,它將返回一個 JSONArray 對象:
List<String> list = new ArrayList<>();
list.add("California");
list.add("Texas");
list.add("Hawaii");
list.add("Alaska");
JSONArray ja = new JSONArray(list);現在我們的 JSONArray 包含以下內容:
["California","Texas","Hawaii","Alaska"]5.4. 從 JSONArray 中移除特定元素
我們可以使用實例方法 remove(int index) 移除特定元素。 讓我們繼續使用名為 ja 的 JSONArray(代表州)並使用 remove(int index) 方法移除“阿拉斯加”元素:
ja.remove(3);之後,我們列出剩餘的 JSONArray:
System.out.println(ja.toString());確實,它並未列出已刪除的元素:
["California","Texas","Hawaii"]進一步,我們還可以從 remove(int index) 方法調用本身中找到被移除的元素,因為該方法返回被移除的元素:
Object removed=ja.remove(3);
System.out.println(removed);確實,它列出了被移除的元素:
Alaska進一步而言,<em>JSONArray</em> 通過移除一個元素,將其大小減少 1。 值得注意的是,<em>JSONArray</em> 中的索引位置是基於零的。 因此,第一個元素位於索引 0。 相應地,如果我們嘗試使用方法調用 <em>ja.remove(4)</em> 移除同一個元素(假設第 4 個元素位於索引 4),該元素不會被移除。 但是,使用非存在的索引位置的調用不會拋出異常/錯誤。 因此,我們應該驗證元素的移除,就像我們所做的那樣。
6. JSONTokener
一個 <em><strong>JSONTokener</strong></em> 接受一個源 <em><strong>String</strong></em> 作為構造函數的輸入,並從中提取字符和標記。它被用於本包中的類(如 <em><strong>JSONObject</strong></em>、`JSONArray)內部解析 JSON String。
可能不會有太多直接使用此類的場景,因為我們可以使用其他更簡單的方法(如 `string.toCharArray())來實現相同的功能。
JSONTokener jt = new JSONTokener("lorem");
while(jt.more()) {
Log.info(jt.next());
}現在我們可以像迭代器一樣訪問一個 JSONTokener,使用 more() 方法來檢查是否有剩餘元素,以及 next() 方法來訪問下一個元素。
以下是來自先前示例接收到的令牌:
l
o
r
e
m7. <em CDL>
我們獲得了 CDL (逗號分隔列表) 類,用於將逗號分隔的文本轉換為 JSONArray,反之亦然。
7.1. 從逗號分隔文本直接生成 JSONArray
要從逗號分隔文本直接生成 JSONArray,我們可以使用靜態方法 rowToJSONArray(),該方法接受一個 JSONTokener。
JSONArray ja = CDL.rowToJSONArray(new JSONTokener("England, USA, Canada"));現在我們的 JSONArray 包含以下內容:
["England","USA","Canada"]7.2. 從 JSONArray 生產逗號分隔的文本
讓我們看看如何反向執行前一步,並從 JSONArray 獲得逗號分隔的文本:
JSONArray ja = new JSONArray("[\"England\",\"USA\",\"Canada\"]");
String cdt = CDL.rowToString(ja);字符串 cdt 現在包含以下內容:
England,USA,Canada7.3. 使用逗號分隔文本生成包含 JSONObject 的 JSONArray
要生成包含 JSONObject 的 JSONArray,我們將使用包含標題和數據,兩者之間用逗號分隔的文本 String。
我們使用回車符 (\r) 或換行符 (\n) 來分隔不同的行。
第一行被解釋為標題列表,而後續的所有行則被視為數據:
String string = "name, city, age \n" +
"john, chicago, 22 \n" +
"gary, florida, 35 \n" +
"sal, vegas, 18";
JSONArray result = CDL.toJSONArray(string);該對象 JSONArray result 現在包含以下內容(為了清晰起見,格式化輸出如下):
[
{
"name": "john",
"city": "chicago",
"age": "22"
},
{
"name": "gary",
"city": "florida",
"age": "35"
},
{
"name": "sal",
"city": "vegas",
"age": "18"
}
]請注意,數據和標題都包含在同一個 String 中。我們提供了一種替代方案,通過提供一個 JSONArray 來獲取標題,以及使用逗號分隔的 String 作為數據,從而實現相同的功能。
再次強調,我們使用換行符 (\r) 或換行符 (\n) 分隔不同的行。
JSONArray ja = new JSONArray();
ja.put("name");
ja.put("city");
ja.put("age");
String string = "john, chicago, 22 \n"
+ "gary, florida, 35 \n"
+ "sal, vegas, 18";
JSONArray result = CDL.toJSONArray(ja, string);在這裏,我們將獲取對象 result} 的內容,與之前完全相同。
8. Cookie
Cookie 類處理 Web 瀏覽器 Cookie,並提供將瀏覽器 Cookie 轉換為 JSONObject 以及反之的方法。
以下是 Cookie 類中的主要方法:
- toJsonObject(String sourceCookie) – 將 Cookie 字符串轉換為 JSONObject
- toString(JSONObject jo) – 前述方法的反向操作,將 JSONObject 轉換為 Cookie String
8.1. 將 Cookie 字符串轉換為 JSONObject
要將 Cookie 字符串轉換為 JSONObject,我們將使用靜態方法 Cookie.toJSONObject():
String cookie = "username=John Doe; expires=Thu, 18 Dec 2013 12:00:00 UTC; path=/";
JSONObject cookieJO = Cookie.toJSONObject(cookie);8.2. 將 JSONObject 轉換為 Cookie 字符串
現在我們將 JSONObject 轉換為 Cookie 字符串。這與之前的步驟相反:
String cookie = Cookie.toString(cookieJO);9. HTTP
HTTP 類包含靜態方法,用於將 HTTP 頭部轉換為 JSONObject,反之亦然。
該類還具有兩個主要方法:
- toJsonObject(String sourceHttpHeader) – 將 HttpHeader String 轉換為 JSONObject
- toString(JSONObject jo) – 將提供的 JSONObject 轉換為 String
9.1. 將 JSONObject 轉換為 HTTP Header
我們使用 HTTP.toString() 方法將 JSONObject 轉換為 HTTP Header String:
JSONObject jo = new JSONObject();
jo.put("Method", "POST");
jo.put("Request-URI", "http://www.example.com/");
jo.put("HTTP-Version", "HTTP/1.1");
String httpStr = HTTP.toString(jo);以下是我們 String httpStr 的內容:
POST "http://www.example.com/" HTTP/1.1請注意,在轉換 HTTP 請求頭時,JSONObject 必須包含 “Method”、“Request-URI” 和 “HTTP-Version” 鍵。 並且對於響應頭,對象必須包含 “HTTP-Version”、“Status-Code” 和 “Reason-Phrase” 參數。
9.2. 將 HTTP Header 字符串 轉換為 JSONObject
在這裏,我們將我們在上一步驟中獲得的 HTTP 字符串轉換為我們上一步驟中創建的 JSONObject:
JSONObject obj = HTTP.toJSONObject("POST \"http://www.example.com/\" HTTP/1.1");10. JSONException
根據上述,基於包式的應用程序在遇到任何錯誤時會拋出 JSONException 標準異常。
org.json 包中使用了該類,並覆蓋在所有其他類中。當應用程序拋出此異常時,它還包含一條消息,説明具體發生了什麼錯誤。
11. 解析 JSON 布爾值
<i>org.json.JSONObject</i> 可能是 Java 中解析 JSON boolean值的最常用類。讓我們探討解析不同表示形式的 boolean值的各種方法。
11.1. 解析 true 和 false
首先,我們從 JSON 字符串中創建一個 JSONObject。然後,我們使用 getBoolean(String)方法獲取 boolean 屬性的值:
@Test
void givenJSONString_whenParsed_thenCorrectBooleanValueReturned() {
String json = """
{
"name": "lorem ipsum",
"active": true,
"id": 1
}
""";
JSONObject jsonObject = new JSONObject(jsonString);
boolean active = jsonObject.getBoolean("active");
assertTrue(active);
}11.2. 解析 0 和 1
通常,我們將 JSON 的 布爾值 表示為 true 或 false。 但是,某些系統可能會使用 0 和 1 來表示一個 布爾值。
我們可以獲取整數值並使用 AssertJ 斷言 assertThat() 來驗證其值為 1:
@Test
void givenJSONWithBooleanAs0Or1_whenParsed_correctBooleanValueReturned() {
String json = """
{
"name": "lorem ipsum",
"active": 1,
"id": 1
}
""";
JSONObject jsonObject = new JSONObject(json);
assertThat(jsonObject.getInt("active")).isEqualTo(1);
}11.3. 解析 JSON 布爾值混合表示
有時,我們知道一個 JSON 屬性包含一個 布爾值;但是,我們不知道它是否以 true/false 或 0/1 的形式表示。 同樣,我們可以從 JSON 字符串中創建 JSONObject,並進一步從 boolean 屬性中創建 Object。
之後,這非常簡單。 如果由此創建的 Object 是 Integer 的實例,則我們使用數值表示。 或者,如果 Object 是 Boolean 的實例,則我們使用布爾值。
我們可以通過將其轉換為適當的類型來從 Object 中獲取 boolean 值:
@Test
void givenJSONWithMixedRepresentationForBoolean_whenParsed_thenCorrectBooleanValueReturned() {
JSONObject jsonObject = new JSONObject(json);
Object activeObject = jsonObject.get("active");
if (activeObject instanceof Integer value) {
assertTrue(value == 1);
} else if (activeObject instanceof Boolean value) {
assertTrue(value);
}
}12. 結論
在本文中,我們探討了使用 Java 庫 org.json 的方法,並重點介紹了該庫中的一些核心功能。