Skip to content

How to Serialize Java Objects to TOON Format Using json-io

Purpose

This post demonstrates how to serialize Java objects to TOON format using the json-io library, including nested structures, collections, and Spring AI integration.

Environment

  • Java 8-24
  • json-io 4.98.0
  • Maven build tool

The json-io Library

json-io provides TOON serialization with a single dependency. It supports Java 8 through 24 and requires only one runtime dependency (java-util).

Add the dependency:

pom.xml
<dependency>
<groupId>com.cedarsoftware</groupId>
<artifactId>json-io</artifactId>
<version>4.98.0</version>
</dependency>

The key methods:

  • JsonIo.toToon(object, options) — Serialize to TOON
  • JsonIo.fromToon(toon, options).asClass(Target.class) — Deserialize to typed object
  • JsonIo.fromToon(toon, options).asType(new TypeHolder<List&lt;T&gt;&gt;(){}) — Deserialize to generic collections

Serializing Single Objects

For a single object, TOON produces YAML-like output:

Person.java
public class Person {
private String name;
private int age;
private String department;
// constructors, getters, setters
}
Serialization example
Person person = new Person("Alice", 28, "Engineering");
String toon = JsonIo.toToon(person, null);
System.out.println(toon);

Output:

TOON output
name: Alice
age: 28
department: Engineering

I can explain the output:

  • Each field is key: value on its own line
  • No braces or quotes needed
  • Clean and readable

Serializing Collections (Tabular Format)

Here’s where TOON shines. Collections of uniform objects automatically use tabular format:

Employee serialization
List<Employee> employees = Arrays.asList(
new Employee("Alice Johnson", 28, "Engineering", 95000),
new Employee("Bob Smith", 34, "Marketing", 78000),
new Employee("Carol White", 31, "Sales", 82000)
);
String toon = JsonIo.toToon(employees, null);
System.out.println(toon);

Output:

Tabular TOON output
[3]{name,age,department,salary}:
Alice Johnson,28,Engineering,95000
Bob Smith,34,Marketing,78000
Carol White,31,Sales,82000

The format breakdown:

  • [3] — Array length
  • {name,age,department,salary} — Field header (declared once!)
  • Following lines — Value rows

This is where the 30-44% token savings come from.

Nested Structures

TOON handles nested structures by mixing formats appropriately:

Nested structure example
Map<String, Object> company = new LinkedHashMap<>();
company.put("name", "Acme Corp");
company.put("founded", 1995);
List<Department> departments = Arrays.asList(
new Department("Engineering", 50),
new Department("Marketing", 20)
);
company.put("departments", departments);
String toon = JsonIo.toToon(company, null);

Output:

Nested TOON output
name: Acme Corp
founded: 1995
departments: [2]{name,employeeCount}:
Engineering,50
Marketing,20

The outer map uses key-value pairs, while the inner array uses tabular format.

Deserializing to Typed Objects

Reading TOON back into Java objects:

Deserialization example
String toon = """
name: Alice
age: 28
department: Engineering
""";
Person person = JsonIo.fromToon(toon, null).asClass(Person.class);
// person.getName() returns "Alice"
// person.getAge() returns 28

Deserializing to Generic Collections

For collections, I need to handle type erasure with TypeHolder:

Collection deserialization
String toon = """
[2]{name,age}:
Alice,28
Bob,34
""";
List<Person> people = JsonIo.fromToon(toon, null)
.asType(new TypeHolder<List<Person>>(){});
// people.size() returns 2
// people.get(0).getName() returns "Alice"

The TypeHolder pattern preserves generic type information at runtime.

Spring AI Integration

For Spring AI applications, there’s a dedicated starter:

pom.xml
<dependency>
<groupId>com.cedarsoftware</groupId>
<artifactId>json-io-spring-ai-toon</artifactId>
<version>4.98.0</version>
</dependency>

Use the ToonToolCallResultConverter to automatically convert tool results:

Spring AI tool example
@Tool(description = "Look up employees by department",
resultConverter = ToonToolCallResultConverter.class)
public List<Employee> findByDepartment(String department) {
return employeeRepository.findByDepartment(department);
}

Now when the LLM calls this tool, the result is automatically in TOON format—saving tokens with zero code changes.

Common Mistakes to Avoid

I made these mistakes when I started:

  1. Using prettyPrint(true) — This reverts to verbose format and eliminates token savings:
Wrong approach
// DON'T do this
String toon = JsonIo.toToon(employees,
new WriteOptions().prettyPrint(true)); // Loses savings!
  1. Forgetting TypeHolder for generic collections — Without it, you get raw Maps instead of typed objects.

  2. Using TOON for service-to-service APIs — External services expect JSON; use toJson() for those.

Summary

In this post, I showed how to serialize Java objects to TOON format using json-io. The key point is that JsonIo.toToon() gives you 30-44% token savings for LLM-bound data with a single method call, while JsonIo.fromToon() reads TOON back into typed Java objects.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments