1. 概述

很长一段时间里,Java 缺乏标准的 JSON 处理方案。开发者主要依赖 Jackson 和 Gson 这类第三方库。

Java EE7 推出了首个官方 JSON 处理 API(JSR 353),而随着 JEE 8 的发布,我们终于迎来了标准化的 JSON 绑定 API(JSR 367)。

当前主流实现包括:

  • Eclipse Yasson(参考实现)
  • Apache Johnzon

2. JSON-B API

2.1. Maven 依赖

先添加核心依赖。注意多数实现会自动传递依赖 javax.json.bind-api

<dependency>
    <groupId>javax.json.bind</groupId>
    <artifactId>javax.json.bind-api</artifactId>
    <version>1.0</version>
</dependency>

最新版本可在 Maven Central 获取。

3. 使用 Eclipse Yasson

Eclipse Yasson 是官方参考实现,完全符合 JSR-367 规范。

3.1. Maven 依赖

集成需添加以下依赖:

<dependency>
    <groupId>org.eclipse</groupId>
    <artifactId>yasson</artifactId>
    <version>1.0.1</version>
</dependency>
<dependency>
    <groupId>org.glassfish</groupId>
    <artifactId>javax.json</artifactId>
    <version>1.1.2</version>
</dependency>

最新版本见 Maven Central

4. 使用 Apache Johnzon

Apache Johnzon 是另一个合规实现,同时支持 JSON-P (JSR-353) 和 JSON-B (JSR-367)。

4.1. Maven 依赖

配置如下:

<dependency>
    <groupId>org.apache.geronimo.specs</groupId>
    <artifactId>geronimo-json_1.1_spec</artifactId>
    <version>1.0</version>
</dependency>
<dependency>
    <groupId>org.apache.johnzon</groupId>
    <artifactId>johnzon-jsonb</artifactId>
    <version>1.1.4</version>
</dependency>

最新版本在 Maven Central

5. API 核心特性

通过注解可灵活定制序列化/反序列化规则。以下示例展示常用配置:

public class Person {

    private int id;

    @JsonbProperty("person-name")
    private String name;
    
    @JsonbProperty(nillable = true)
    private String email;
    
    @JsonbTransient  // 忽略该字段
    private int age;
     
    @JsonbDateFormat("dd-MM-yyyy")
    private LocalDate registeredDate;
    
    private BigDecimal salary;
    
    @JsonbNumberFormat(locale = "en_US", value = "#0.0")
    public BigDecimal getSalary() {
        return salary;
    }
 
    // 标准getter/setter
}

序列化后输出:

{
   "email":"john@example.com",
   "id":1,
   "person-name":"Jhon",
   "registeredDate":"07-09-2019",
   "salary":"1000.0"
}

关键注解说明:

  • @JsonbProperty:自定义字段名
  • @JsonbTransient:排除字段
  • 📅 @JsonbDateFormat:日期格式化
  • 🔢 @JsonbNumberFormat:数字格式化
  • ⚠️ @JsonbNillable:允许null值序列化

5.1. 序列化与反序列化

使用 JsonbBuilder 进行转换。创建对象:

Person person = new Person(
  1, 
  "Jhon", 
  "john@example.com", 
  20, 
  LocalDate.of(2019, 9, 7), 
  BigDecimal.valueOf(1000));

执行序列化:

Jsonb jsonb = JsonbBuilder.create();
String jsonPerson = jsonb.toJson(person);

反序列化:

Person person = jsonb.fromJson(jsonPerson, Person.class);

集合处理

List<Person> personList = Arrays.asList(...);
String jsonArrayPerson = jsonb.toJson(personList);

输出示例:

[ 
    {
      "email":"john@example.com",
      "id":1,
      "person-name":"Jhon", 
      "registeredDate":"09-09-2019",
      "salary":"1000.0"
    },
    {
      "email":"alice@example.com",
      "id":2,
      "person-name":"Alice",
      "registeredDate":"09-09-2019",
      "salary":"1500.0"
    }
]

JSON数组转List:

List<Person> personList = jsonb.fromJson(
  personJsonArray, 
  new ArrayList<Person>(){}.getClass().getGenericSuperclass()
);

5.2. 全局配置(JsonbConfig)

通过 JsonbConfig 统一修改命名策略、属性顺序等全局规则。

命名策略示例(下划线分隔):

JsonbConfig config = new JsonbConfig()
    .withPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CASE_WITH_UNDERSCORES);
Jsonb jsonb = JsonbBuilder.create(config);
String jsonPerson = jsonb.toJson(person);

输出:

{
   "email":"john@example.com",
   "id":1,
   "person-name":"Jhon",
   "registered_date":"07-09-2019",  // 注意字段名变化
   "salary":"1000.0"
}

属性顺序策略(逆序):

JsonbConfig config = new JsonbConfig()
    .withPropertyOrderStrategy(PropertyOrderStrategy.REVERSE);
Jsonb jsonb = JsonbBuilder.create(config);

输出:

{
    "salary":"1000.0",
    "registeredDate":"07-09-2019",
    "person-name":"Jhon",
    "id":1,
    "email":"john@example.com"
}

5.3. 自定义适配器(Adapters)

当注解和全局配置无法满足需求时,通过适配器实现深度定制。

实现 JsonbAdapter 接口:

public class PersonAdapter implements JsonbAdapter<Person, JsonObject> {

    @Override
    public JsonObject adaptToJson(Person p) {
        return Json.createObjectBuilder()
          .add("id", p.getId())
          .add("name", p.getName())
          .build();
    }

    @Override
    public Person adaptFromJson(JsonObject adapted) {
        Person person = new Person();
        person.setId(adapted.getInt("id"));
        person.setName(adapted.getString("name"));
        return person;
    }
}

注册适配器:

JsonbConfig config = new JsonbConfig()
    .withAdapters(new PersonAdapter());
Jsonb jsonb = JsonbBuilder.create(config);

输出结果(仅包含id和name):

{
    "id":1, 
    "name":"Jhon"
}

6. 总结

本文介绍了 JSON-B API 的核心用法,包括:

  1. 主流实现集成(Yasson/Johnzon)
  2. 序列化/反序列化基础操作
  3. 注解驱动的字段级定制
  4. 全局配置策略
  5. 高级适配器模式

完整示例代码可在 GitHub 获取。踩坑提醒:适配器与注解同时存在时,适配器优先级更高,需注意配置冲突。


原始标题:Intro to the JSON Binding API (JSR 367) in Java