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();
}

代码虽稍显啰嗦,但逻辑很简单:

  1. 创建 JsonWriterFactory 实例,传入配置映射
  2. 映射中设置 PRETTY_PRINTINGtrue
  3. 使用工厂实例创建写入器(而非 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

  1. getJsonArray() 获取 "pets" 列表(返回 3 条记录)
  2. getJsonObject(2) 获取列表中的第三个对象(索引从 0 开始)
  3. 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;
            }
        }   
    }
}

⚠️ 代码逻辑解析:

  1. 使用 Json.createParser() 创建解析器
  2. 通过迭代器遍历 JSON 标记(前向访问特性)
  3. 检查每个标记的类型(Event
  4. 当遇到第三次 "name" 键时,获取其值

对于复杂 JSON 结构,流式 API 确实更难用。选择哪种方式取决于具体场景:

  • ✅ 对象模型 API:简单直观,适合中小型 JSON
  • ✅ 流式 API:高效内存,适合大型 JSON 或仅需少量数据的情况

5. 总结

我们通过几个简单示例覆盖了 Java EE JSON 处理 API 的核心功能。想了解更多 JSON 处理技巧,可以参考我们的 Jackson 系列文章

本文使用的类源码及单元测试可在 GitHub 仓库 中查看。


原始标题:JSON Processing in Java EE 7