Interface Codec<T>

Type Parameters:
T - the type this codec converts
All Known Implementing Classes:
Base32Codec, Base64Codec, ChecksumCodec, CompressionStreamCodec, DeflateCodec, EnvelopeCodec, GzipCodec, HexCodec, Lz4Codec, StringCodec, ZstdCodec

public interface Codec<T>
Converts values of type T to and from byte[].

Implementations must be symmetric: decode(encode(value)) yields a value equal to the original. Codecs are expected to be thread-safe.

Failures. Every failure encode or decode reports is a CodecException for the codecs this library provides; a codec derived with xmap(Function, Function) also propagates whatever the caller's conversion functions throw. More precisely, a CodecException is one of four families keyed to what the caller does next: InvalidValueException (fix the value), InvalidPayloadException (quarantine the payload), UnsupportedFormatException (hold it for a newer reader), TransientCodecException (retry). Implementations wrap their underlying library's exception as the cause rather than letting it escape. A null argument is a programmer error and throws NullPointerException; see nullSafe() for the explicit pass-through.

  • Method Summary

    Modifier and Type
    Method
    Description
    default Codec<T>
    andThen(Codec<byte[]> transform)
    Layers a byte-level transform (compression, encryption, etc.) onto this codec.
    decode(byte[] bytes)
    Decodes bytes back into a value.
    byte[]
    encode(T value)
    Encodes a value to bytes.
    default Codec<T>
    Wraps this codec so that null passes straight through in both directions: encode(null) returns null and decode(null) returns null, without consulting this codec.
    default <U> Codec<U>
    xmap(Function<? super T, ? extends U> forward, Function<? super U, ? extends T> backward)
    Derives a codec for another type from this one, given a conversion in each direction.
  • Method Details

    • encode

      byte[] encode(T value)
      Encodes a value to bytes.
      Parameters:
      value - the value to encode
      Returns:
      the encoded bytes
      Throws:
      InvalidValueException - if the value cannot be encoded by this codec
      TransientCodecException - if something the codec depends on failed
      NullPointerException - if value is null and this codec does not accept null
    • decode

      T decode(byte[] bytes)
      Decodes bytes back into a value.
      Parameters:
      bytes - the bytes to decode
      Returns:
      the decoded value
      Throws:
      InvalidPayloadException - if the bytes are malformed, corrupt, or forged
      UnsupportedFormatException - if the bytes are well-formed but in a format this codec cannot read
      TransientCodecException - if something the codec depends on failed
      NullPointerException - if bytes is null and this codec does not accept null
    • andThen

      default Codec<T> andThen(Codec<byte[]> transform)
      Layers a byte-level transform (compression, encryption, etc.) onto this codec.

      The returned codec applies transform.encode after this codec's encode, and transform.decode before this codec's decode. Chained transforms compose outward on encode and unwind automatically in reverse order on decode:

      EnvelopeCodec envelope = EnvelopeCodec.builder(provider).build();
      Codec<Person> codec = factory.create(Person.class).andThen(new GzipCodec()).andThen(envelope);
      
      Parameters:
      transform - the byte transform to apply after encoding (and invert before decoding)
      Returns:
      a codec of the same type with the transform applied
      Throws:
      NullPointerException - if transform is null
    • nullSafe

      default Codec<T> nullSafe()
      Wraps this codec so that null passes straight through in both directions: encode(null) returns null and decode(null) returns null, without consulting this codec. Every other value is delegated unchanged.

      Whether a bare codec accepts null is up to its implementation — a JSON backend encodes it as the literal null, the transforms reject it — so this is the explicit form for integrations whose contract treats null as "absent", such as cache serializers that are handed null on a miss.

      Returns:
      a codec that maps null to null and otherwise behaves as this one
    • xmap

      default <U> Codec<U> xmap(Function<? super T, ? extends U> forward, Function<? super U, ? extends T> backward)
      Derives a codec for another type from this one, given a conversion in each direction.

      Where andThen(Codec) wraps the bytes side of a codec, this wraps the value side: the returned codec encodes a U by converting it to a T with backward and then encoding it here, and decodes by decoding a T here and converting it with forward. It is the tool for the domain-type-versus-wire-type split — a backend that only serializes generated or registered classes, wrapped as the type the application actually uses:

      Codec<Person> codec = factory.create(PersonProto.class).xmap(Person::fromProto, Person::toProto);
      

      Exceptions thrown by either function propagate unchanged.

      Type Parameters:
      U - the derived codec's type
      Parameters:
      forward - converts a decoded T to a U
      backward - converts a U to the T this codec encodes
      Returns:
      a codec for U
      Throws:
      NullPointerException - if either function is null