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 中央仓库 获取。
⚠️ 注意:使用 Android SDK 时无需显式添加此依赖,因为 Android 已内置该包。
3. Java 中的 JSON 处理 [org.json 包]
我们使用 JSON-Java 库中的类来解析和操作 JSON。该库也称为 org.json,切勿与 Google 的 org.json.simple 库混淆。
此外,该库还支持 JSON 与 XML、HTTP 头、Cookie、逗号分隔列表或文本等格式之间的转换。
本教程将重点介绍以下核心类:
- JSONObject:类似 Java 原生 Map 的对象,存储无序的键值对
- JSONArray:类似 Java 原生 Vector 的有序值序列
- JSONTokener:将文本分解为一系列标记(token)的工具,供 JSONObject 或 JSONArray 解析 JSON 字符串
- CDL:提供逗号分隔文本与 JSONArray 相互转换的方法
- Cookie:JSON 字符串与 Cookie 相互转换
- HTTP:JSON 字符串与 HTTP 头相互转换
- JSONException:库抛出的标准异常
4. JSONObject
JSONObject 是键值对的无序集合,类似 Java 原生 Map 实现:
- 键是唯一的非空 String
- 值可以是 Boolean、Number、String、JSONArray 甚至 JSONObject.NULL 对象
- JSONObject 可表示为花括号包裹的字符串,键值对用冒号分隔,元素间用逗号分隔
- 提供多种构造方法创建 JSONObject
主要方法包括:
- *get(String key)*:获取指定键关联的对象,键不存在时抛出 JSONException
- *opt(String key)*:获取指定键关联的对象,键不存在时返回 null
- *put(String key, Object value)*:插入或替换当前 JSONObject 中的键值对
put() 方法已重载,支持多种值类型。完整方法列表见官方文档。
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
也可先构建自定义 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.1 节相同。
4.3. 从 JSON String 创建 JSONObject
将 JSON 字符串传给构造方法即可解析(注意转义双引号):
JSONObject jo = new JSONObject(
"{\"city\":\"chicago\",\"name\":\"jon doe\",\"age\":\"22\"}"
);
⚠️ 传入的字符串必须是有效 JSON,否则构造方法会抛出 JSONException。
4.4. 从 JSON 字符串解析值
构建 JSONObject 实例后,使用对应的 get 方法获取属性值。对于嵌套的 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:
DemoBean demo = new DemoBean();
demo.setId(1);
demo.setName("lorem ipsum");
demo.setActive(true);
JSONObject jo = new JSONObject(demo);
生成的 JSONObject:
{
"name":"lorem ipsum",
"active":true,
"id":1
}
✅ 虽然支持 Java 对象转 JSON,但该库不支持反向转换。如需双向转换,建议使用 Jackson 等库。
5. JSONArray
JSONArray 是值的有序集合,类似 Java 原生 Vector 实现:
- 值可以是 Number、String、Boolean、JSONArray、JSONObject 甚至 JSONObject.NULL
- 表示为方括号包裹的字符串,值间用逗号分隔
- 构造方法接受源字符串并解析为 JSONArray
主要方法包括:
- *get(int index)*:返回指定索引(0 到 length-1)的值,越界抛出 JSONException
- *opt(int index)*:返回指定索引的值,越界返回 null
- *put(Object value)*:向 JSONArray 末尾追加值(已重载支持多种数据类型)
完整方法列表见官方文档。
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
构造方法支持直接解析 JSON 字符串:
JSONArray ja = new JSONArray("[true, \"lorem ipsum\", 215]");
⚠️ 若字符串不是有效 JSON,构造方法会抛出 JSONException。
5.3. 从集合或数组创建 JSONArray
构造方法支持 Collection 或数组作为参数:
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) 移除特定元素。继续使用州名示例,移除 "Alaska":
ja.remove(3);
输出剩余元素:
System.out.println(ja.toString());
// ["California","Texas","Hawaii"]
✅ remove(int index) 返回被移除的元素:
Object removed = ja.remove(3);
System.out.println(removed); // Alaska
⚠️ 移除元素后 JSONArray 长度减 1。索引从 0 开始,尝试移除不存在的索引(如 *ja.remove(4)*)不会抛异常,需自行验证。
6. JSONTokener
JSONTokener 接受源字符串并从中提取字符和标记。该库内部类(如 JSONObject、JSONArray)使用它解析 JSON 字符串。
直接使用场景较少,因其他方法(如 *string.toCharArray()*)可替代:
JSONTokener jt = new JSONTokener("lorem");
while(jt.more()) {
Log.info(jt.next());
}
输出标记:
l
o
r
e
m
7. CDL
CDL(逗号分隔列表)提供逗号分隔文本与 JSONArray 的相互转换。
7.1. 从逗号分隔文本生成 JSONArray
使用静态方法 *rowToJSONArray()*,接受 JSONTokener 参数:
JSONArray ja = CDL.rowToJSONArray(new JSONTokener("England, USA, Canada"));
生成的 JSONArray:
["England","USA","Canada"]
7.2. 从 JSONArray 生成逗号分隔文本
反向操作:
JSONArray ja = new JSONArray("[\"England\",\"USA\",\"Canada\"]");
String cdt = CDL.rowToString(ja);
生成的字符串:
England,USA,Canada
7.3. 使用逗号分隔文本生成 JSONObject 数组
文本需同时包含表头和数据,用回车(\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(格式化后):
[
{
"name": "john",
"city": "chicago",
"age": "22"
},
{
"name": "gary",
"city": "florida",
"age": "35"
},
{
"name": "sal",
"city": "vegas",
"age": "18"
}
]
✅ 替代方案:单独提供表头 JSONArray 和数据字符串:
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);
结果与之前相同。
8. Cookie
Cookie 类处理浏览器 Cookie,提供 Cookie 字符串与 JSONObject 的相互转换。
主要方法:
- *toJsonObject(String sourceCookie)*:将 Cookie 字符串转为 JSONObject
- *toString(JSONObject jo)*:将 JSONObject 转为 Cookie 字符串
8.1. Cookie 字符串转 JSONObject
String cookie = "username=John Doe; expires=Thu, 18 Dec 2013 12:00:00 UTC; path=/";
JSONObject cookieJO = Cookie.toJSONObject(cookie);
8.2. JSONObject 转 Cookie 字符串
String cookie = Cookie.toString(cookieJO);
9. HTTP
HTTP 类提供 HTTP 头与 JSONObject 的相互转换。
主要方法:
- *toJsonObject(String sourceHttpHeader)*:HTTP 头字符串转 JSONObject
- *toString(JSONObject jo)*:JSONObject 转 HTTP 头字符串
9.1. JSONObject 转 HTTP 头
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);
生成的 HTTP 头:
POST "http://www.example.com/" HTTP/1.1
⚠️ 转换请求头时 JSONObject 必须包含 "Method"、"Request-URI" 和 "HTTP-Version" 键;响应头需包含 "HTTP-Version"、"Status-Code" 和 "Reason-Phrase"。
9.2. HTTP 头字符串转 JSONObject
JSONObject obj = HTTP.toJSONObject("POST \"http://www.example.com/\" HTTP/1.1");
10. JSONException
JSONException 是库抛出的标准异常,包含错误详情信息。该库所有类均使用此异常。
11. 解析 JSON 布尔值
org.json.JSONObject 是 Java 中解析 JSON 布尔值最常用的类。
11.1. 解析 true 和 false
从 JSON 字符串创建 JSONObject,使用 getBoolean(String) 获取布尔属性:
@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
某些系统用 0/1 表示布尔值。获取整数值后用 AssertJ 验证:
@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. 解析混合布尔表示
当不确定布尔值是 true/false 还是 0/1 时:
@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 的 JSON 处理库——org.json,重点展示了其核心功能。该库简单粗暴,适合基础 JSON 操作,但复杂场景建议搭配 Jackson/Gson 等库使用。