使用jakarta.json进行json序列化和反序列化
引言
java里,json框架何其多,常见的有jackson、fastjson、gson等。各自的api互不相通,与代码耦合度高,切换json库的代码修改工作量非常大。如果使用json的api为统一的入口,各家再进行实现,代码与实现类不耦合,像slf4j一样,切换log框架(log4j/logback等)也不用改代码,代码只对api依赖,不对具体的实现依赖,那就很好了。
jakarta.json项目就是为了解决这个问题的。自从javax改名jakarta,并全部给eclipse基金会运营,jakarta.json作为Jakarta EE子项目之一也得到了支持。
引入依赖
<dependency>
<groupId>jakarta.json.bind</groupId>
<artifactId>jakarta.json.bind-api</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>org.eclipse</groupId>
<artifactId>yasson</artifactId>
<version>3.0.3</version>
</dependency>
jakarta.json.bind-api是jsonb的接口包,里面只有对象定义、接口定义等,没有代码实现。yasson则对jsonb规范进行了完整实现。
将一个JsonObject序列化为字符串(JSON)
JsonObject jsonObject = Json.createObjectBuilder()
.add("name", "John")
.add("age", 12)
.add("remark", "This is a test")
.add("birthDate", LocalDate.parse("2020-01-01").toString())
.add("hobbies", Json.createArrayBuilder().add("football").add("basketball"))
.add("members", Json.createArrayBuilder().add(Json.createObjectBuilder().add("rel", "son").add("name", "Lilei").build()))
.build();
System.out.println(jsonObject.toString());
注:JsonObject
的带包名类名是jakarta.json.JsonObject
,位于
<dependency>
<groupId>jakarta.json</groupId>
<artifactId>jakarta.json-api</artifactId>
<version>2.1.3</version>
</dependency>
以上代码打印结果:
{"name":"John","age":12,"remark":"This is a test","birthDate":"2020-01-01","hobbies":["football","basketball"],"members":[{"rel":"son","name":"Lilei"}]}
将一个对象序列化为json字符串(JSONB)
@Test
void serialize() {
User user = new User("John", 12, "This is a test", LocalDate.parse("2020-01-01"));
String json = JsonbBuilder.create().toJson(user);
System.out.println(json);
}
注:JsonbBuilder
是jakarta.json.bind.JsonbBuilder
,位于:
<dependency>
<groupId>jakarta.json.bind</groupId>
<artifactId>jakarta.json.bind-api</artifactId>
<version>3.0.1</version>
</dependency>
将一个对象序列化为json字符串(格式化)
@Test
void prettySerialize() {
User user = new User("John", 12, "This is a test", LocalDate.parse("2020-01-01"));
String json = JsonbBuilder.create(new JsonbConfig().withFormatting(true)).toJson(user);
System.out.println(json);
}
将一个json字符串反序列化为一个对象
public record User(String name, int age, String remark, LocalDate birthDate) { }
@Test
void deserialize() {
String json = """
{
"name": "John",
"age": 12,
"remark": "This is a test",
"birthDate": "2020-01-01"
}
""";
User user = JsonbBuilder.create().fromJson(json, User.class);
System.out.println("user = " + user);
}
面向接口编程
以上代码,去掉
<dependency>
<groupId>org.eclipse</groupId>
<artifactId>yasson</artifactId>
<version>3.0.3</version>
</dependency>
代码编译不会报错,但运行时会提示没有有效的provider,因为代码依赖的是jakarta.json、jakarta.json.bind两个api包,不影响代码编译。
但api只定义了接口、方法入参及返回类型、数据对象结构,自身并没有逻辑代码,所以无法实现对象的序列化和反序列化。
探密yasson
yasson之所以能在代码不依赖org.eclipse.yasson.*的情况下实现对对象进行JSON序列化和反序列化。是因为
yasson包里定义jakarta.json.bind的SPI
SPI的写法(Java8及之前)
定义SPI文件META-INF/services/jakarta.json.bind.spi.JsonbProvider
,META-INF/services/
是固定写法,jakarta.json.bind.spi.JsonbProvider
是接口/抽象类的类名,作为该文件名。
org.eclipse.yasson.JsonBindingProvider
文件里只有一行代码,指定了org.eclipse.yasson.JsonBindingProvider
是jakarta.json.bind.spi.JsonbProvider
的实现类。
SPI的写法(Java9及之后)
使用module-info.java来定义依赖的模块、对外开放的模块、SPI,其中SPI使用以下语法来对接口进行指定实现类:
写法:
provides 接口类 with 实现类;
yasson的完整module-info
module org.eclipse.yasson {
requires jakarta.json;
requires jakarta.json.bind;
requires java.logging;
requires static java.xml;
requires static java.naming;
requires static java.sql;
requires static java.desktop;
requires static jakarta.cdi;
exports org.eclipse.yasson;
exports org.eclipse.yasson.spi;
provides jakarta.json.bind.spi.JsonbProvider with org.eclipse.yasson.JsonBindingProvider;
uses org.eclipse.yasson.spi.JsonbComponentInstanceCreator;
}
手写一个json实现库
一样的写法,依赖的接口和数据对象是jakarta.json、jakarta.json.bind,实现逻辑则由自己进行实现。
实现后,按上面的SPI方法定义实现类,然后把pom里的yasson依赖去掉,加上自己的依赖。
系统加载时,会自动发现SPI的实现类。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)