Kryo v6 Follow ups - EsotericSoftware/kryo GitHub Wiki

Open items found in the reviews of kryo-6 and postponed, or still open, checked against the code on 2026-10-13. Not planned for a particular release. Decisions and done items are in Kryo v6 Ideas.

Fixes without a format change

  • An application subclass of TimeZone without its own default serializer is read back as TimeZone.getTimeZone(id), a different class.
  • CalendarSerializer creates the written Calendar class (Calendar.Builder for the buddhist and japanese calendars) and TimeZoneSerializer throws on write for an unknown ID instead of writing GMT. Branch calendar-timezone, undecided because the second is a behavior change.

Format changes (gated with Format.KRYO5, golden file lengths and a MIGRATION entry)

  • Arrays.asList: a reference to the list from one of its elements resolves to the temporary ArrayList. Needs a copy of CollectionSerializer.read (~50 lines).
  • LocaleSerializer drops the extensions of a Locale without a script, like Kryo 5.
  • ZonedDateTime loses the offset in a DST overlap. Write the offset and read with ZonedDateTime.ofLocal (~15 lines).
  • The Kryo 5 format writes the registered type name (java.util.TimeZone, java.nio.charset.Charset, enums with bodies) where Kryo 5 wrote the implementation class. Both read both. Kept so far, documented in Kryo5RoundTripTest.classNameDiffers.

Performance

  • ChunkedEncoding.get looks the encoding up in the context, a Kryo field would be +1 to 2% for chunked encoding but is an API change.
  • Code generation: create the object in the generated code with a constant constructor method handle, then call kryo.reference and read the fields in the same generated method. A prototype without the checks measured +6.8% (ObjectGraphBenchmark.field, references on) and +8.4% (references off). It may only be used when Kryo would call the zero argument constructor anyway: create not overridden, the default instantiator strategy and no instantiator set on the registration, also if one is set later. Branch codegen-new-ceiling, not pushed.
  • Code generation: batching the sets of final fields when reflection is denied. Measured on JDK 27 with a Serializable class of 10 fields: each final field costs about 150 ns per object under deny, because FinalFieldSetter sets all serializable fields of the class per call, with and without code generation (round trip with code generation 100 ns allowed, 385/835/1,590 ns denied for 2/5/10 final fields). One call per class would be about 250 ns, 1.5x to 6x faster. Idea: the generated code keeps the values of final fields in locals and sets them with one call before the next field that may refer to the object and at the end, decided when the code is generated, so no state at runtime. Deny is opt-in until a Java release makes it the default, maybe for the next LTS. Proof of concept: https://github.com/EsotericSoftware/kryo/pull/1515 (draft), 2.1x to 4.1x faster under deny with 5 to 10 final fields, ~1.15x with 2.
  • Shared CachedFields across Kryo instances, stage 2 of the shared metadata. The shared Field objects are the big win already.

API and features

  • A code generation switch on Kryo, like kryo.setReferences, instead of a FieldSerializerFactory with a config just to turn it on. Decide before the release.

Build, CI and release

  • The README links to a kryo-5 branch that doesn't exist yet. Cut it from the last 5.x tag at the release.
  • OSS-Fuzz (https://github.com/google/oss-fuzz/tree/master/projects/kryo) builds master with JDK 17, which fails for Kryo 6. Fix: build with JDK 25 and copy the runtime dependencies, works for master too: https://github.com/google/oss-fuzz/pull/16284 (open, needs approval by a past contributor of the project). Optionally a fuzzer for the chunked encoding of CompatibleFieldSerializer, which the three fuzzers don't reach.
  • Android: the sequenced collection wrappers on Android 35 aren't covered by tests, desugared lambdas are serialized silently with FieldSerializer (README note?), optional Kryo 5 backport of the ExternalizableSerializer ClassValue fix.
  • Bump the kryo5 test dependency of Kryo5RoundTripTest after each 5.x release.

Kryo 5 line (master)