1. 概述
本文将展示如何仅使用 Java EE 核心功能处理 JSON,无需依赖 Jersey 或 Jackson 等第三方库。我们主要使用的工具包来自 javax.json
包,这是 Java EE 7 的原生 JSON 处理方案。
2. 将 Java 对象转换为 JSON 字符串
把 Java 对象转成 JSON 字符串非常简单。假设我们有一个简单的 Person
类:
public class Person {
private String firstName;
private String lastName;
private Date birthdate;
// getters and setters
}
要将该类的实例转为 JSON 字符串,首先需要创建 JsonObjectBuilder
实例,并通过 add()
方法添加属性/值对:
JsonObjectBuilder objectBuilder = Json.createObjectBuilder()
.add("firstName", person.getFirstName())
.add("lastName", person.getLastName())
.add("birthdate", new SimpleDateFormat("DD/MM/YYYY")
.format(person.getBirthdate()));
注意 add()
方法有多个重载版本,可以接收大多数基本类型(及其包装类)作为第二个参数。
设置完属性后,只需将对象写入字符串:
JsonObject jsonObject = objectBuilder.build();
String jsonString;
try(Writer writer = new StringWriter()) {
Json.createWriter(writer).write(jsonObject);
jsonString = writer.toString();
}
搞定!生成的字符串如下:
{"firstName":"Michael","lastName":"Scott","birthdate":"06/15/1978"}
2.1. 使用 JsonArrayBuilder 构建数组
现在给示例增加点难度:假设 Person
类新增了一个 emails
属性,包含多个邮箱地址:
public class Person {
private String firstName;
private String lastName;
private Date birthdate;
private List<String> emails;
// getters and setters
}
要将列表中的所有值添加到 JsonObjectBuilder
,需要借助 JsonArrayBuilder
:
JsonArrayBuilder arrayBuilder = Json.createArrayBuilder();
for(String email : person.getEmails()) {
arrayBuilder.add(email);
}
objectBuilder.add("emails", arrayBuilder);
这里使用了另一个重载的 add()
方法,它接受 JsonArrayBuilder
对象作为参数。
对于包含两个邮箱的 Person
对象,生成的字符串如下:
{"firstName":"Michael","lastName":"Scott","birthdate":"06/15/1978",
"emails":["michael.scott@dundermifflin.com","michael@worldbestboss.com"]}
2.2. 使用 PRETTY_PRINTING 格式化输出
成功转成 JSON 字符串后,让我们添加简单格式化使其更易读。
之前示例中,我们直接使用 Json.createWriter()
创建 JsonWriter
。现在要控制输出格式,需借助 Java 7 的 JsonWriterFactory
创建带特定配置的写入器:
Map<String, Boolean> config = new HashMap<>();
config.put(JsonGenerator.PRETTY_PRINTING, true);
JsonWriterFactory writerFactory = Json.createWriterFactory(config);
String jsonString;
try(Writer writer = new StringWriter()) {
writerFactory.createWriter(writer).write(jsonObject);
jsonString = writer.toString();
}
代码虽稍显啰嗦,但逻辑很简单:
- 创建
JsonWriterFactory
实例,传入配置映射 - 映射中设置
PRETTY_PRINTING
为true
- 使用工厂实例创建写入器(而非
Json.createWriter()
)
格式化后的输出包含换行和缩进:
{
"firstName":"Michael",
"lastName":"Scott",
"birthdate":"06/15/1978",
"emails":[
"michael.scott@dundermifflin.com",
"michael@worldbestboss.com"
]
}
3. 从 JSON 字符串构建 Java 对象
现在执行反向操作:将 JSON 字符串转为 Java 对象。
转换的核心是 JsonObject
类。通过静态方法 Json.createReader()
和 readObject()
创建实例:
JsonReader reader = Json.createReader(new StringReader(jsonString));
JsonObject jsonObject = reader.readObject();
createReader()
接收 InputStream
参数。本例使用 StringReader
(因为 JSON 在字符串中),但同样可用于读取文件(如使用 FileInputStream
)。
有了 JsonObject
实例后,通过 getString()
方法读取属性并赋值给新创建的 Person
对象:
Person person = new Person();
person.setFirstName(jsonObject.getString("firstName"));
person.setLastName(jsonObject.getString("lastName"));
person.setBirthdate(dateFormat.parse(jsonObject.getString("birthdate")));
3.1. 使用 JsonArray 获取列表值
提取列表值需要特殊类 JsonArray
:
JsonArray emailsJson = jsonObject.getJsonArray("emails");
List<String> emails = new ArrayList<>();
for (JsonString j : emailsJson.getValuesAs(JsonString.class)) {
emails.add(j.getString());
}
person.setEmails(emails);
✅ 完成!我们已从 JSON 字符串完整创建了 Person
对象。
4. 查询特定值
假设需要从 JSON 字符串中提取特定数据。考虑以下宠物店客户的 JSON,我们需要获取宠物列表中第三只宠物的名字:
{
"ownerName": "Robert",
"pets": [{
"name": "Kitty",
"type": "cat"
}, {
"name": "Rex",
"type": "dog"
}, {
"name": "Jake",
"type": "dog"
}]
}
为获取单个值而转换整个对象并不高效。以下是两种无需完全转换即可查询 JSON 字符串的策略:
4.1. 使用对象模型 API 查询
当知道属性在 JSON 结构中的位置时,查询很简单。使用前例中的 JsonObject
类:
JsonReader reader = Json.createReader(new StringReader(jsonString));
JsonObject jsonObject = reader.readObject();
String searchResult = jsonObject
.getJsonArray("pets")
.getJsonObject(2)
.getString("name");
关键点在于使用正确的 get*()
方法序列导航 jsonObject
:
- 用
getJsonArray()
获取 "pets" 列表(返回 3 条记录) - 用
getJsonObject(2)
获取列表中的第三个对象(索引从 0 开始) - 用
getString()
提取目标值
4.2. 使用流式 API 查询
另一种精确查询方式是流式 API(Streaming API),核心类是 JsonParser
。
JsonParser
提供极速的只读前向访问,但比对象模型 API 更复杂:
JsonParser jsonParser = Json.createParser(new StringReader(jsonString));
int count = 0;
String result = null;
while(jsonParser.hasNext()) {
Event e = jsonParser.next();
if (e == Event.KEY_NAME) {
if(jsonParser.getString().equals("name")) {
jsonParser.next();
if(++count == 3) {
result = jsonParser.getString();
break;
}
}
}
}
⚠️ 代码逻辑解析:
- 使用
Json.createParser()
创建解析器 - 通过迭代器遍历 JSON 标记(前向访问特性)
- 检查每个标记的类型(
Event
) - 当遇到第三次 "name" 键时,获取其值
对于复杂 JSON 结构,流式 API 确实更难用。选择哪种方式取决于具体场景:
- ✅ 对象模型 API:简单直观,适合中小型 JSON
- ✅ 流式 API:高效内存,适合大型 JSON 或仅需少量数据的情况
5. 总结
我们通过几个简单示例覆盖了 Java EE JSON 处理 API 的核心功能。想了解更多 JSON 处理技巧,可以参考我们的 Jackson 系列文章。
本文使用的类源码及单元测试可在 GitHub 仓库 中查看。