You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Every failure Codec.encode and Codec.decode report is now a CodecException from codec-core, in one of four families keyed to what the
caller does next: InvalidValueException (fix the value), InvalidPayloadException (quarantine), UnsupportedFormatException (hold for
a newer reader), TransientCodecException (retry). Anything catching IllegalArgumentException, IllegalStateException, UncheckedIOException, ClassCastException, or a Jackson/Gson/JSON-B/Fory/protobuf exception from encode/decode must catch the family (or CodecException) instead; the
library's exception is still there as the cause. Construction-time exceptions
are unchanged. codec-crypto's DecryptionException, KeyAccessException
and EncryptionException keep their names and messages and now extend InvalidPayloadException, TransientCodecException and TransientCodecException respectively; an unknown envelope version or
algorithm id is now UnsupportedFormatException, not a rejection. codec-versioned's UnknownVersionException now extends UnsupportedFormatException and is no longer a VersionedFormatException.
See the new Handling failures
guide.
Base32Codec.standard() and .hex() decode canonically: upper case only, and
non-zero trailing bits in the final symbol are rejected (MZ====== is an
error; MY====== is f). Callers who fed lower-case input opt back in with .caseInsensitive()
Changed
The build compiles with -Xlint:all,-processing,-unchecked -Werror: any javac
warning in an enabled category fails compilation. unchecked is off because TypeRef.rawClass() is the one unchecked cast the type system cannot express;
no other is permitted. The Gson, Protobuf and Fory backends no longer carry
unchecked casts, and every exception class declares a serialVersionUID
codec-gson encodes by the codec's declared type (Gson.toJson(value, type))
rather than the value's runtime class, matching what decode already did; a
polymorphic value now serialises as its declared T
codec-fory: Apache Fory 1.1.0 → 1.7.1. ForyCodecFactory.of(...) takes Fory's
defaults, and Fory's default changed from schema-consistent to compatible mode
in 1.2.0 (without a release note), so payloads now carry their class schema:
a reader whose class has gained or lost a field decodes correctly where
schema-consistent mode silently returned a mis-shifted object. It costs a few
bytes per class per message — a lone four-field record roughly doubles, a
100-item order grows 2%; throughput is unchanged. Payloads written by earlier
releases still decode, but bytes written by this release cannot be read by a
schema-consistent Fory. Callers who want a specific mode build their own ThreadSafeFory and pass it to the constructor. Per Fory's security guidance
the helper also sets deserializeUnknownClass(false), so a payload naming an
unregistered class is rejected rather than materialised as an anonymous struct
JacksonCodecFactory, Jackson2CodecFactory, and GsonCodecFactory now reject a null engine or TypeRef with a labelled NullPointerException, matching the
JSON-B and Fory factories; CompressionStreamCodec likewise rejects null on encode and decode before touching a stream, matching the other transforms
Added
TypeRef.rawClass(): the erased class of the captured type, typed Class<T>,
so a backend can use the checked Class.cast instead of an unchecked cast of
its own. It is the single unchecked cast in the codebase and its Javadoc says so
codec-versioned: VersionedCodec prefixes each payload with a magic and
version header and dispatches decoding on it, so a storage strategy can change
without a flag day — old versions stay registered and readable while an
explicit write version makes a two-phase rollout possible
codec-benchmarks: JMH benchmarks for every compression transform (deflate
and zstd at several levels), encoding, backend (a small record and a
100-item object graph), and the envelope-encryption strategies (not
published), with the results and a benchmarks page in the docs
Base32Codec.of(alphabet) and of(alphabet, pad): a strict codec over any
32-symbol ASCII alphabet, with caseInsensitive() and aliasing(...) as
decode-side opt-ins; crockford() (ULIDs), zBase32() and geohash()
presets. The encode and decode loops are specialised for whole groups, about
4x the throughput of the previous implementation
Documentation
Fixed a newcomer-walkthrough review's findings: the Composition guide's
chaining sample and the Codec.andThen Javadoc snippet now build EnvelopeCodec (there is no AesCodec); the landing page states the Java
25 / Spring Boot 4.x requirement; the landing page and Getting Started link
Apache Kafka and Spring Data Redis; the Guides nav orders Handling Failures
before Evolving Stored Formats; the Kafka guide covers RecordDeserializationException/ErrorHandlingDeserializer and declares
its config variable; the Spring Boot guide states what happens with no
backend on the classpath; and the Redis guide turns its auto-configuration
prerequisites into a checklist and adds a codec.redis.cache.* properties
table
Benchmarks re-run on 2026-09-06 with Fory 1.7.1, zstd-jni 1.5.7-15, and
lz4-java 1.11.2: zstd decodes 1 MB payloads 18–29% faster at every level, the
backend numbers and encoded sizes reflect Fory's compatible mode, and the Fory
guide gains a schema-evolution section
Compression claims corrected against the benchmarks: the JDK codecs are
fastest on payloads under a few hundred bytes, zstd's default level is not
smaller than gzip on prose, and LZ4-HC is a decode-side optimisation
New guide, Evolving Stored Formats:
how codec-versioned works, a worked upgrade, the fleet rollout order, and
what belongs inside the versioned codec versus outside it
The aggregated Javadoc for every module is published with the site at jwcarman.github.io/codec/api, one set
per release, built from the release tag