A zero-copy, SIMD-accelerated ASON serialization library for Java 21+. Benchmarked against JSON via Gson in the JVM ecosystem.
- ClassMeta + MethodHandle invokeExact: Pre-computed per-class metadata with pre-adapted MethodHandles. Primitive fields use type-specific
invokeExact(e.g.,(Object)->int) with zero boxing/adaptation overhead - SIMD Acceleration: Uses
jdk.incubator.vector(ByteVector 256-bit/128-bit) for fast character scanning — special char detection, escape scanning, delimiter search - ThreadLocal Buffer Pool:
ByteBufferwith ThreadLocal reuse (up to 1MB), 2× growth factor — eliminates allocation for repeated encode calls - ISO-8859-1 Fast String Construction: Both encoder and decoder detect ASCII-only content and use
ISO_8859_1charset for direct byte-copy String construction (vs UTF-8 validation overhead) - Single-Pass Fused Write:
writeStringcombines classify + write in one pass with rollback on special chars — no separate analysis pass - CHAR_CLASS Lookup Table: 128-byte classification table replaces 6+ per-character comparisons for ASON delimiter detection
- POW10 Direct Double Parsing: Decoder parses
intPart + fracVal / POW10[fracDigits]avoidingStringallocation for simple decimals - Type-Tag Switch Dispatch: Integer-tagged field types (T_BOOLEAN=0 .. T_STRUCT=11) for O(1) dispatch in both encode and decode
- DEC_DIGITS Fast Formatting: 200-byte lookup table for two-digit integer formatting, eliminates division-per-digit overhead
- Binary Format: Little-endian wire format with zero parsing overhead — direct memory reads for primitives
- Schema-Driven:
{field1,field2}:(val1,val2)format eliminates redundant key repetition in arrays - No Native Map Type: keyed collections are modeled explicitly as entry lists such as
attrs@[{key@str,value@int}]
import io.ason.Ason;
// Text encode/decode
String text = Ason.encode(obj); // untyped schema
String typed = Ason.encodeTyped(obj); // with type annotations
T obj = Ason.decode(text, MyClass.class); // single struct
List<T> list = Ason.decodeList(text, MyClass.class); // list of structs
// byte[] decode (avoids String→byte[] conversion)
T obj = Ason.decode(bytes, MyClass.class);
List<T> list = Ason.decodeList(bytes, MyClass.class);
// Binary encode/decode
byte[] bin = Ason.encodeBinary(obj);
T obj = Ason.decodeBinary(bin, MyClass.class);
List<T> list = Ason.decodeBinaryList(bin, MyClass.class);Bundled Kotlin extensions provide inline reified helpers for idiomatic Kotlin usage:
import io.ason.decode
import io.ason.decodeList
val user: User = decode(text)
val users: List<User> = decodeList(text)Packaging note:
- The main
ason-javaartifact includes the Kotlin helper layer. - Because of that, the published runtime dependency set includes
kotlin-stdlib-jdk8. - Java users can ignore the Kotlin APIs; they do not change the Java-facing API surface.
Note on Kotlin Data Classes: ASON currently targets zero-dependency maximum performance using raw reflection. To use Kotlin data class, please ensure:
- Use
varfor properties instead ofval. - Provide default values for all properties (this forces Kotlin to generate the required no-arg constructor behind the scenes).
- Plain nullable types (e.g.,
String?) are completely natively supported and do not requireOptional<T>.
Example compatible data class:
data class User(
var id: Long = 0,
var name: String? = null,
var active: Boolean = false
)Single struct:
{name,age,active}:(Alice,30,true)
Array (schema-driven — schema written once):
[{name,age,active}]:(Alice,30,true),(Bob,25,false)
Typed schema:
{name@str,age@int,active@bool}:(Alice,30,true)
Nested struct:
{id,dept}:(1,(Engineering))
Entry-list collection:
{attrs@[{key@str,value@int}]}:([(age,30),(score,95)])
Native Map<K,V> fields are intentionally unsupported in the current format. Use a List<Entry>-style model instead.
Run the bundled benchmark example:
./gradlew runBenchExampleThe Java benchmark now uses the same JSON/ASON/BIN output style as the Go benchmark:
Flat struct × 500 (8 fields, vec)
Serialize: JSON 16.22ms/60784B | ASON 10.11ms(1.6x)/28327B(46.6%) | BIN 4.92ms(3.3x)/37230B(61.2%)
Deserialize: JSON 22.09ms | ASON 5.70ms(3.9x) | BIN 2.11ms(10.5x)
(46.6%) means the ASON payload is 46.6% of the JSON size, not “saved 46.6%”.
Gson uses Java reflection for field access and tree-based intermediate representations. ASON achieves 2–5x better performance through format advantages and JIT-friendly design:
- No Key Repetition: JSON repeats every key for every object. ASON writes the schema once, then only values — 53% smaller output means less memory bandwidth.
- No Quoting Overhead: ASON only quotes strings that contain special characters — most strings are emitted raw, saving
"delimiter overhead. - MethodHandle invokeExact: Pre-adapted handles match JIT-optimized direct field access. No boxing for primitives, no type adaptation at call site — vs Gson's reflection-based
Field.get()/Field.set(). - SIMD Scanning: Character classification uses 256-bit vector operations, processing 32 bytes per cycle.
- ThreadLocal Buffer Pool: Reuses up to 1MB byte buffers, eliminating allocation pressure in the encode hot path.
- ISO-8859-1 String Fast Path: ASCII-only strings (the common case) use
ISO_8859_1charset for direct byte-copy construction — 2-3x faster than UTF-8 validation. - Direct Double Parsing: POW10 lookup table parses
intPart + fracVal / 10^nwithout String allocation — avoidsDouble.parseDouble()for simple decimals. - No Intermediate Tree: Gson builds
JsonElementtrees during parsing. ASON decodes directly into target objects with zero intermediate allocations.
| ASON Type | ASON Text | ASON Binary |
|---|---|---|
bool |
true/false |
1 byte (0/1) |
int |
decimal | 4/8/2/1 bytes LE |
float |
decimal | 4/8 bytes IEEE754 LE |
str |
plain or "quoted" |
u32 length + UTF-8 |
char |
single char string | 2 bytes LE |
Optional<T> |
value or empty | u8 tag + payload |
List<T> |
[v1,v2,...] |
u32 count + elements |
| Entry-list collection | [(k1,v1),(k2,v2)] |
u32 count + elements |
| Nested struct | (f1,f2,...) |
fields in order |
Native Map<K,V> fields are intentionally unsupported. Model keyed data as an explicit entry struct list instead.
# Requirements: JDK 21+, Gradle 9.1+ (wrapper included)
./gradlew test
./gradlew runBasicExample
./gradlew runComplexExample
./gradlew runBenchExamplesrc/main/java/io/ason/
├── Ason.java — Public API + text encoder (CHAR_CLASS, DEC_DIGITS, single-pass writeString)
├── ClassMeta.java — Per-class metadata cache (FieldMeta, MethodHandle invokeExact, type tags)
├── AsonDecoder.java — SIMD-accelerated text decoder (POW10, skipWs, ISO-8859-1 fast path)
├── AsonBinary.java — Binary codec (LE wire format)
├── ByteBuffer.java — ThreadLocal byte buffer pool (1MB max, 2× growth, ASCII tracking)
├── SimdUtils.java — SIMD utilities (ByteVector 256/128)
├── AsonException.java — Runtime exception
└── examples/
├── BasicExample.java — 12 basic examples
├── ComplexExample.java — 14 complex examples
└── BenchExample.java — Full benchmark suite (JSON / ASON / BIN)
Benchmark results vary by JDK, CPU, and heap settings. For the current machine, run:
./gradlew runBenchExampleThat example prints the canonical JSON/ASON/BIN comparison format used across the language implementations in this repository.