TOON (Text-Oriented Object Notation) 是专为大型语言模型(LLM)交互设���的轻量级数据序列化格式,兼顾人类可读性与Token优化,比JSON节省30-60%的API调用成本。本库是TOON规范在Java 8环境下的生产级实现。
- 为Java开发者提供低Token消耗的LLM交互数据格式,降低API调用成本;
- 保持高可读性,让开发者与LLM都能快速理解数据结构;
- 支持复杂业务场景(嵌套对象、集合、自定义类型),兼容JDK 1.8及以上;
- 提供灵活扩展能力,满足不同业务的类型转换、字段注释等个性化需求。
| 特性 | 说明 |
|---|---|
| 🚀 Token优化 | 表格化数据存储+元数据前置压缩,比JSON平均节省30-60% Token,大幅降低LLM调用成本 |
| 🧠 LLM友好 | 支持字段注释,元数据显式约束,减少模型解析幻觉,提升交互准确率 |
| 📦 全面兼容 | 支持基础类型、集合、嵌套对象、枚举、LocalDateTime等常用类型 |
| 🔌 灵活扩展 | 自定义类型转换器、字段注释、序列化策略,适配复杂业务场景 |
| ⚡ 性能高效 | 反射字段缓存,避免重复解析类结构,高频场景性能提升50%以上 |
| 🛡️ 健壮可靠 | 精细化异常体系+特殊字符处理,生产环境稳定可用 |
- ✅ 支持所有Java基础类型及包装类(int/Integer、long/Long等)
- ✅ 支持String、枚举、LocalDateTime等常用类型
- ✅ 支持List/Set集合类型,自动校验数据长度
- ✅ 支持嵌套对象(无限层级),通过缩进标识层级关系
- ✅ 字段注释:通过
@ToonField(comment="")为字段添加说明,LLM可直���理解 - ✅ 自定义类型转换器:扩展支持Date、BigDecimal等业务类型
- ✅ 特殊字符处理:自动转义逗号、分号等分隔符,避免格式破坏
- ✅ 反射缓存:缓存类字段结构,提升高频序列化/反序列化性能
- ✅ 精细化异常:区分格式错误、类型转换失败、反射异常等场景,便于调试
- 兼容JDK 1.8及以上版本
- 与TOON规范v1.3完全兼容
- 支持与JSON格式双向转换(需自行集成Jackson等JSON库)
<dependency>
<groupId>com.github</groupId>
<artifactId>toon-java</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>static class Address {
@com.github.toon.anno.ToonField(order = 1, comment = "街道地址,含门牌号和单元号")
private String street;
@com.github.toon.anno.ToonField(order = 2, comment = "城市名称")
private String city;
public Address() {} // 反序列化需要默认构造函数
public Address(String street, String city) {
this.street = street;
this.city = city;
}
// getter和setter(序列化需要访问字段值)
public String getStreet() { return street; }
public String getCity() { return city; }
}
enum UserStatus {
ACTIVE, INACTIVE
}
static class User {
@com.github.toon.anno.ToonField(order = 1, comment = "用户唯一标识,自增ID")
private int id;
@com.github.toon.anno.ToonField(order = 2, comment = "用户姓名,最长32字符")
private String name;
@com.github.toon.anno.ToonField(order = 3, comment = "注册时间,ISO格式")
private LocalDateTime registerTime;
@com.github.toon.anno.ToonField(order = 4, comment = "用户状态(ACTIVE/INACTIVE)")
private UserStatus status;
@com.github.toon.anno.ToonField(order = 5, comment = "用户地址信息")
private Address address;
public User() {} // 反序列化需要默认构造函数
public User(int id, String name, LocalDateTime registerTime, UserStatus status, Address address) {
this.id = id;
this.name = name;
this.registerTime = registerTime;
this.status = status;
this.address = address;
}
// getter和setter
public int getId() { return id; }
public String getName() { return name; }
public LocalDateTime getRegisterTime() { return registerTime; }
public UserStatus getStatus() { return status; }
public Address getAddress() { return address; }
}import com.github.toon.Toons;
import com.github.toon.exception.ToonException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
public class QuickStartDemo {
public static void main(String[] args) throws ToonException {
// 1. 构建测试数据(含特殊字符、嵌套对象、枚举类型)
Address homeAddr = new Address("123 Main St, Apt 4B", "New York"); // 包含逗号的字符串
Address workAddr = new Address("456 Business Ave", "San Francisco");
User user1 = new User(
1,
"Alice",
LocalDateTime.of(2024, 1, 1, 10, 30),
UserStatus.ACTIVE,
homeAddr
);
User user2 = new User(
2,
"Bob",
LocalDateTime.of(2024, 2, 15, 14, 20),
UserStatus.INACTIVE,
workAddr
);
List<User> userList = new ArrayList<>();
userList.add(user1);
userList.add(user2);
// 2. 执行序列化(使用全局工具类)
String toonStr = Toons.serialize("users", userList);
System.out.println("集合序列化结果:\n" + toonStr);
}
}TOON序列化结果:
users(2){id#用户唯一标识,自增ID,name#用户姓名,最长32字符,registerTime#注册时间,ISO格式,status#用户状态(ACTIVE/INACTIVE),address#用户地址信息[$object],address.street#街道地址,含门牌号和单元号,address.city#城市名称}:
1,Alice,2024-01-01T10:30:00,ACTIVE,(123 Main St\, Apt 4B,New York);
2,Bob,2024-02-15T14:20:00,INACTIVE,(456 Business Ave,San Francisco);
import com.github.toon.converter.TypeConverter;
import com.github.toon.exception.ToonTypeConvertException;
import java.math.BigDecimal;
// 自定义BigDecimal转换器
public class BigDecimalConverter implements TypeConverter {
@Override
public boolean support(Class<?> type) {
return BigDecimal.class.equals(type);
}
@Override
public Object convert(String value, Class<?> type) throws ToonTypeConvertException {
if (value == null || value.trim().isEmpty()) {
return null;
}
try {
return new BigDecimal(value.trim());
} catch (NumberFormatException e) {
throw new ToonTypeConvertException("", type, value);
}
}
@Override
public String serialize(Object value) {
return value == null ? "" : value.toString();
}
}
// 注册转换器
public class ConverterDemo {
public static void main(String[] args) throws ToonException {
DefaultToonSerializer serializer = new DefaultToonSerializer();
serializer.addConverter(new BigDecimalConverter());
DefaultToonDeserializer deserializer = new DefaultToonDeserializer();
deserializer.addConverter(new BigDecimalConverter());
// 后续序列化/反序列化可自动处理BigDecimal类型
}
}import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.toon.exception.ToonException;
import java.util.List;
public class MixedFormatDemo {
public static void main(String[] args) throws Exception {
// 1. 构建数据
Address addr = new Address("123 Main St", "New York");
List<User> users = List.of(new User(1, "Alice", LocalDateTime.now(), addr));
// 2. JSON序列化(存储/持久化)
ObjectMapper objectMapper = new ObjectMapper();
String jsonStr = objectMapper.writeValueAsString(users);
// 4. 转换为TOON(与LLM交互)
String toonStr = Toons.serialize("users", jsonData);
System.out.println("TOON格式(入模用):");
System.out.println(toonStr);
}
}- LLM API 调用:按 Token 计费的场景(如 OpenAI、Anthropic),大幅降低调用成本;
- RAG 系统:知识库数据传输,兼顾可读性与传输效率;
- AI Agent 交互:结构化指令传输,字段注释帮助 Agent 理解数据含义;
- 成本敏感型 AI 项目:需要控制 API 开销的大规模 LLM 应用。
- 需跨语言极致兼容性(优先 JSON);
- 深度嵌套的非表格化数据(JSON 更高效);
- 对序列化速度要求极高且数据结构简单(可考虑 Protobuf)。
- Fork 本仓库;
- 创建特性分支(git checkout -b feature/xxx);
- 提交代码(git commit -m "feat: 新增xxx功能");
- 推送分支(git push origin feature/xxx);
- 提交 Pull Request。
- 遵循 Google Java Code Style;
- 新增功能需配套单元测试(覆盖率≥80%);
- 不破坏原有 API 兼容性(除非重大版本迭代)。
本项目基于 Apache License 2.0 开源,可自由用于商业和非商业项目。