Developers
9 TOP-LEVEL ITEMSMultiFieldCodec
MultiFieldCodec<T> is built on top of MapCodec<T> and lets one field accept several different key names. It is especially useful for renamed fields, aliases, and backward compatibility.
Where MultiCodec solves "multiple value formats," MultiFieldCodec solves "multiple names for the same field."
Core idea
Its behavior is:
- during decoding, look through several candidate keys in order
- return the first one that exists and decodes successfully
- during encoding, always write back to the first key name
That makes it naturally suited for cases where reading should be compatible, but writing should converge on one canonical name.
For example, if you want both of these forms to work:
{ "id": 1 }and:
{ "index": 1 }you can map both onto the same field with MultiFieldCodec.
CodecUtil.fieldsOf(...)
In real code, you usually do not instantiate MultiFieldCodec directly. The normal entry point is CodecUtil.fieldsOf(...):
MapCodec<MyType> codec = RecordCodecBuilder.mapCodec(instance -> instance.group(
CodecUtil.fieldsOf(Codec.INT, "id", "index").forGetter(MyType::getId)
).apply(instance, MyType::new));This means:
- accept both
idandindexduring decoding - always encode back as
id
It is a very natural fit for smooth field renames.
OptionalMultiFieldCodec
OptionalMultiFieldCodec<T> is the optional variant of the same idea.
Its difference is:
- if none of the candidate keys exist, it returns
Optional.empty() - if candidate keys exist but all of them fail to decode, it returns an error
That makes it a better choice for:
- optional fields
- compatibility with old field names when the field itself is not mandatory
In practice, the common entry point is CodecUtil.optionalFieldsOf(...).
CodecUtil.optionalFieldsOf(...)
Croparia IF exposes two common forms:
- one that returns
OptionalMultiFieldCodec<T> - one that accepts a default value and returns a normal
MapCodec<T>
For example:
MapCodec<Integer> codec = CodecUtil.optionalFieldsOf(Codec.INT, 0, "id", "index");That means:
idandindexare both accepted- if neither key exists, use the default value
0 - when encoding, only the first key name is written
If you want to preserve the meaning of "present versus absent," prefer the optional form and handle the Optional<T> yourself.
When to use it
Good use cases:
- a field was renamed, but old configs still need to load
- one concept historically used more than one name
- you want to expose a friendlier alias while still keeping legacy compatibility
Poor use cases:
- the names differ because the underlying meaning has already diverged
- you are only trying to avoid writing proper field definitions
If the semantics behind two names have already split, they should no longer be merged into one MultiFieldCodec.
Tips
- Since encoding always writes the first key name, make sure that first name is the one you want to keep long-term.
- If the field is genuinely optional, prefer
optionalFieldsOf(...)instead of mixing "missing field" and "failed parse" into one behavior. - When one field starts collecting too many aliases, it is often a sign that the config model itself needs to be cleaned up.
- If you also need multiple key names and multiple value formats, it is completely fine to combine
MultiFieldCodecwith MultiCodec.