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 的核心用法,包括:
- 主流实现集成(Yasson/Johnzon)
- 序列化/反序列化基础操作
- 注解驱动的字段级定制
- 全局配置策略
- 高级适配器模式
完整示例代码可在 GitHub 获取。踩坑提醒:适配器与注解同时存在时,适配器优先级更高,需注意配置冲突。