⚠️ Beta Status (v0.1.x): This library is in active development and working towards spec compliance. Beta published to Maven Central. API may change before 1.0.0 release.
Compact, human-readable serialization format for LLM contexts with 30-60% token reduction vs JSON. Combines YAML-like indentation with CSV-like tabular arrays. Working towards full compatibility with the official TOON specification.
Key Features: Minimal syntax • TOON Encoding and Decoding • Tabular arrays for uniform data • Array length validation • Java 17 • Comprehensive test coverage.
JToon is available on Maven Central. Add it to your project using your preferred build tool:
Gradle (Groovy DSL):
dependencies {
implementation 'dev.toonformat:jtoon:0.1.4'
}Gradle (Kotlin DSL):
dependencies {
implementation("dev.toonformat:jtoon:0.1.4")
}Maven:
<dependency>
<groupId>dev.toonformat</groupId>
<artifactId>jtoon</artifactId>
<version>0.1.4</version>
</dependency>Note: See the latest version on Maven Central (also shown in the badge above).
You can also download the JAR directly from the GitHub Releases page and add it to your project's classpath.
import dev.toonformat.jtoon.JToon;
import java.util.*;
record User(int id, String name, List<String> tags, boolean active, List<?> preferences) {}
record Data(User user) {}
User user = new User(123, "Ada", List.of("reading", "gaming"), true, List.of());
Data data = new Data(user);
System.out.println(JToon.encode(data));Output:
user:
id: 123
name: Ada
tags[2]: reading,gaming
active: true
preferences[0]:
Some Java-specific types are automatically normalized for LLM-safe output:
| Input Type | Output |
|---|---|
| Number (finite) | Decimal form; -0 → 0; whole numbers as integers |
Number (NaN, ±Infinity) |
null |
BigInteger |
Integer if within Long range, otherwise string (no quotes) |
BigDecimal |
Decimal number |
LocalDateTime |
ISO date-time string in quotes |
LocalDate |
ISO date string in quotes |
LocalTime |
ISO time string in quotes |
ZonedDateTime |
ISO zoned date-time string in quotes |
OffsetDateTime |
ISO offset date-time string in quotes |
Instant |
ISO instant string in quotes |
java.util.Date |
ISO instant string in quotes |
Optional<T> |
Unwrapped value or null if empty |
Stream<T> |
Materialized to array |
Map |
Object with string keys |
Collection, arrays |
Arrays |
Converts any Java object or JSON-string to TOON format.
Parameters:
value– Any Java object (Map, List, primitive, or nested structure). Non-serializable values are converted tonull. Java temporal types are converted to ISO strings, Optional is unwrapped, and Stream is materialized.options– Optional encoding options (EncodeOptionsrecord):indent– Number of spaces per indentation level (default:2)delimiter– Delimiter enum for array values and tabular rows:Delimiter.COMMA(default),Delimiter.TAB, orDelimiter.PIPElengthMarker– Boolean to prefix array lengths with#(default:false)
For encodeJson overloads:
json– A valid JSON string to be parsed and encoded. Invalid or blank JSON throwsIllegalArgumentException.
Returns:
A TOON-formatted string with no trailing newline or spaces.
Example:
import dev.toonformat.jtoon.JToon;
import java.util.*;
record Item(String sku, int qty, double price) {}
record Data(List<Item> items) {}
Item item1 = new Item("A1", 2, 9.99);
Item item2 = new Item("B2", 1, 14.5);
Data data = new Data(List.of(item1, item2));
System.out.println(JToon.encode(data));Output:
items[2]{sku,qty,price}:
A1,2,9.99
B2,1,14.5
String json = """
{
"user": {
"id": 123,
"name": "Ada",
"tags": ["reading", "gaming"]
}
}
""";
System.out.println(JToon.encodeJson(json));Output:
user:
id: 123
name: Ada
tags[2]: reading,gaming
The delimiter option allows you to choose between comma (default), tab, or pipe delimiters for array values and tabular rows. Alternative delimiters can provide additional token savings in specific contexts.
Using tab delimiters instead of commas can reduce token count further, especially for tabular data:
import dev.toonformat.jtoon.*;
import java.util.*;
record Item(String sku, String name, int qty, double price) {}
record Data(List<Item> items) {}
Item item1 = new Item("A1", "Widget", 2, 9.99);
Item item2 = new Item("B2", "Gadget", 1, 14.5);
Data data = new Data(List.of(item1, item2));
EncodeOptions options = new EncodeOptions(2, Delimiter.TAB, false);
System.out.println(JToon.encode(data, options));Output:
items[2 ]{sku name qty price}:
A1 Widget 2 9.99
B2 Gadget 1 14.5
Benefits:
- Tabs are single characters and often tokenize more efficiently than commas.
- Tabs rarely appear in natural text, reducing the need for quote-escaping.
- The delimiter is explicitly encoded in the array header, making it self-descriptive.
Considerations:
- Some terminals and editors may collapse or expand tabs visually.
- String values containing tabs will still require quoting.
Pipe delimiters offer a middle ground between commas and tabs:
// Using the same Item and Data records from above
EncodeOptions options = new EncodeOptions(2, Delimiter.PIPE, false);
System.out.println(JToon.encode(data, options));Output:
items[2|]{sku|name|qty|price}:
A1|Widget|2|9.99
B2|Gadget|1|14.5
The lengthMarker option adds an optional hash (#) prefix to array lengths to emphasize that the bracketed value represents a count, not an index:
import dev.toonformat.jtoon.*;
import java.util.*;
record Item(String sku, int qty, double price) {}
record Data(List<String> tags, List<Item> items) {}
Item item1 = new Item("A1", 2, 9.99);
Item item2 = new Item("B2", 1, 14.5);
Data data = new Data(List.of("reading", "gaming", "coding"), List.of(item1, item2));
System.out.println(JToon.encode(data, new EncodeOptions(2, Delimiter.COMMA, true)));
// tags[#3]: reading,gaming,coding
// items[#2]{sku,qty,price}:
// A1,2,9.99
// B2,1,14.5
// Works with custom delimiters
System.out.println(JToon.encode(data, new EncodeOptions(2, Delimiter.PIPE, true)));
// tags[#3|]: reading|gaming|coding
// items[#2|]{sku|qty|price}:
// A1|2|9.99
// B2|1|14.5Converts TOON-formatted strings back to Java objects or JSON.
Parameters:
toon– TOON-formatted input stringoptions– Optional decoding options (DecodeOptionsrecord):indent– Number of spaces per indentation level (default:2)delimiter– Expected delimiter:Delimiter.COMMA(default),Delimiter.TAB, orDelimiter.PIPEstrict– Boolean for validation mode. Whentrue(default), throwsIllegalArgumentExceptionon invalid input. Whenfalse, returnsnullon errors.
Returns:
For decode: A Java object (Map for objects, List for arrays, primitives for scalars, or null)
For decodeToJson: A JSON string representation
Example:
import dev.toonformat.jtoon.JToon;
String toon = """
users[2]{id,name,role}:
1,Alice,admin
2,Bob,user
""";
// Decode to Java objects
Object result = JToon.decode(toon);
// Decode directly to JSON string
String json = JToon.decodeToJson(toon);import dev.toonformat.jtoon.*;
import java.util.*;
// Original data
Map<String, Object> data = new LinkedHashMap<>();
data.put("id", 123);
data.put("name", "Ada");
data.put("tags", Arrays.asList("dev", "admin"));
// Encode to TOON
String toon = JToon.encode(data);
// Decode back to objects
Object decoded = JToon.decode(toon);
// Values are preserved (note: integers decode as Long)import dev.toonformat.jtoon.*;
String toon = "tags[3|]: a|b|c";
// Decode with pipe delimiter
DecodeOptions options = new DecodeOptions(2, Delimiter.PIPE, true);
Object result = JToon.decode(toon, options);
// Lenient mode (returns null on errors instead of throwing)
DecodeOptions lenient = DecodeOptions.withStrict(false);
Object result2 = JToon.decode(invalidToon, lenient);CI/CD: GitHub Actions • Java 17 • Coverage enforcement • PR coverage comments
This project is 100% compliant with TOON specification. Release conformance enforced on CI/CD.
See CONTRIBUTING.md for detailed guidelines.
- 📘 Full Documentation - Extended guides and references
- 🔧 API Reference - Detailed Javadoc
- 📋 Format Specification - TOON syntax and rules
- 📜 TOON Spec - Official specification
- 🐛 Issues - Bug reports and features
- 🤝 Contributing - Contribution guidelines
MIT License – see LICENSE for details