最近在浏览 json.org 官网时,一个熟悉的名字跃入眼帘——json-io。
这个库我大概十年前用过,当时选择它的理由很简单:零配置、支持循环引用、不需要给实体类加一堆注解。后来 Jackson 和 Gson 成了市场主流,json-io 也就渐渐淡出了我的视野。
没想到,这位“老将”最近搞了个大动作:全面支持 TOON 格式的读写。
TOON 是什么?简单来说,它是一种专门为大型语言模型(LLM)设计的数据格式,比传统的 JSON 能节省 30% 到 60% 的 Token 数量。现在调用 LLM API 可是按 Token 计费的,这个数字意味着实打实的成本节约。
一个已有十年历史的库,突然切入火热的 人工智能 赛道,这件事本身就挺有意思。
TOON 是什么?
TOON,全称 Token-Oriented Object Notation,即面向 Token 的对象表示法。
它大概在 2025 年底开始在开发者社区流行起来,TypeScript、Python、Go 等语言都有了相应的实现,但 Java 生态一直缺少一个成熟可靠的方案。
我们先看一个直观的对比。
JSON 格式:
{
"name": "John Smith",
"age": 30,
"email": "john@example.com",
"active": true,
"roles": ["admin", "user"]
}
TOON 格式:
name: John Smith
age: 30
email: john@example.com
active: true
roles:
- admin
- user
差别一目了然:TOON 格式去掉了引号、花括号、逗号等“语法噪音”,仅用缩进来表示层级结构。正是这些被去掉的字符,直接带来了 30% 到 60% 的 Token 节省。
你可能会问:这不就是 YAML 吗?并不完全是。TOON 是专门针对 LLM 应用场景进行优化的格式,它在精简的同时保留了类型信息,并支持 Schema 感知。实际测试表明,LLM 解析 TOON 的准确率通常比解析 YAML 更高。
json-io 的前世今生
json-io 是由 John DeRegnaucourt 开发的一个 Java JSON 库,第一版发布于 2012 年。
当年它能受到欢迎,主要得益于以下几个特点:
1. 零配置
不需要在实体类上加任何注解,直接就能序列化和反序列化:
String json = JsonIo.toJson(myObject);
MyClass obj = JsonIo.toJava(json).asClass(MyClass.class);
2. 支持循环引用
这个能力,即便是 Jackson 和 Gson 至今也没有原生的完美支持。json-io 通过 @id 和 @ref 机制来处理对象间的循环引用:
{
"@id": 1,
"name": "parent",
"child": {
"name": "child",
"parent": {"@ref": 1}
}
}
3. 自动处理多态类型
不需要像使用 Jackson 那样配置 @JsonTypeInfo。当需要时,json-io 会自动添加 @type 字段来标识具体的子类类型。
4. 轻量级
json-io 的核心 jar 包只有 330K 左右,加上其依赖的 java-util 库,总大小也就在 1MB 上下。相比之下,Jackson 的全家桶通常超过 2.5MB。
正是这些特性,让 json-io 被 json.org 官网收录,成为早期 Java 生态中推荐的 JSON 库之一。
为什么要支持 TOON?
2026 年 1 月,json-io 发布了 4.85.0 版本,正式宣布支持 TOON 格式。
作者 John DeRegnaucourt 在 dev.to 上写了一篇文章解释初衷:他看到社区里关于 TOON 的讨论越来越多,但实现大多集中在 TypeScript、Python、Go 等语言,Java 生态明显落后了。作为 json-io 的作者,他决定亲自填补这个空白。
这个理由很务实。随着 LLM 应用越来越普及,Java 开发者确实需要一个趁手的 TOON 处理工具。
json-io 的 TOON 实现有几个突出亮点,我们通过和另一个早期 Java TOON 库 JToon 的对比来看:
| 能力 |
json-io |
JToon |
| 内置类型 |
60+ |
~15 |
| Map Key 类型 |
任意可序列化类型 |
仅字符串 |
| EnumSet |
支持 |
不支持 |
| 循环引用 |
支持 |
不支持 |
| 依赖 |
java-util |
Jackson |
| 状态 |
稳定 |
Beta |
支持 60+ 种内置类型是什么概念?像 LocalDateTime、BigDecimal、UUID、Path 这些 JDK 中的常用类型,json-io 都能直接序列化和反序列化,完全不需要开发者编写自定义的 Converter。在实际项目中,这能省去不少繁琐的配置工作。
快速上手
添加依赖
Maven:
<dependency>
<groupId>com.cedarsoftware</groupId>
<artifactId>json-io</artifactId>
<version>4.89.0</version>
</dependency>
Gradle:
implementation 'com.cedarsoftware:json-io:4.89.0'
基础用法
下面是一个简单的演示:
import com.cedarsoftware.io.JsonIo;
import java.util.List;
public class ToonDemo {
public static void main(String[] args) {
// 创建对象
User user = new User("lengleng", 18, List.of("admin", "user"));
// 序列化为 JSON
String json = JsonIo.toJson(user);
System.out.println("JSON:\n" + json);
// 序列化为 TOON(省 ~40% token)
String toon = JsonIo.toToon(user, null);
System.out.println("TOON:\n" + toon);
// 从 TOON 反序列化
User restored = JsonIo.fromToon(toon, null).asClass(User.class);
System.out.println("Restored: " + restored.getName());
}
}
运行后,输出对比非常明显:
JSON:
{"name":"lengleng","age":18,"roles":["admin","user"]}
TOON:
name: lengleng
age: 18
roles:
- admin
- user
Restored: lengleng
可以看到,TOON 格式非常简洁,去除了所有不必要的符号。
Spring Boot 集成
json-io 还贴心地提供了 Spring Boot Starter,支持基于内容协商的自动格式转换。
首先添加 Starter 依赖:
<dependency>
<groupId>com.cedarsoftware</groupId>
<artifactId>json-io-spring-boot-starter</artifactId>
<version>4.89.0</version>
</dependency>
你的 Controller 不需要任何改动:
@RestController
public class UserController {
@GetMapping("/user/{id}")
public User getUser(@PathVariable Long id) {
return userService.findById(id);
}
}
客户端只需要通过 Accept 请求头来指定想要的格式即可:
# 请求 JSON 格式(保持对外兼容)
curl -H "Accept: application/json" http://localhost:8080/user/1
# 请求 TOON 格式(内部LLM调用,节省成本)
curl -H "Accept: application/vnd.toon" http://localhost:8080/user/1
这个设计非常优雅。对外提供的 API 可以继续使用 JSON 以保持兼容性,而当内部服务需要调用 LLM 时,可以无缝切换到 TOON 格式来节约 Token 成本,一举两得。
配合 Spring AI 使用
如果你已经在使用 Spring Boot 进行 AI 应用开发,还可以这样配置,让 Tool 调用的响应也使用 TOON 格式:
@Bean
public ToolResponseFormatConverter toonConverter() {
return new ToonToolResponseFormatConverter();
}
Spring 官方博客在 2025 年 11 月曾专门介绍过这种用法,这说明 TOON 格式已经进入了主流技术视野。
总结
json-io 这次对 TOON 格式的支持,可以看作是一次成功的“老兵新传”。它凭借自身稳定、灵活的特性,及时地填补了 Java 生态在 LLM 数据格式处理上的一个空白。对于正在或计划将 LLM 能力集成到 Java 应用中的开发者来说,这无疑是一个值得关注的工具。在按 Token 计费的成本压力下,一行代码就能换来可观的费用节省,这样的优化显得尤为实在。
不难预见,为了在 AI 时代保持竞争力,未来可能会有更多像 Jackson、FastJson 这样的主流库加入对 TOON 的支持。技术的浪潮总是推着人向前,而善于利用新工具,正是开发者在 云栈社区 这类技术论坛中持续交流和成长的意义所在。