Interface SerializeDeserialize<V>
- Type Parameters:
V- the deserialized type
This class is responsible for loading values and converting them into the appropriate type, and vice versa.
Implementations can also perform updates of the source value. Such updating is performed by the default method
deserializeUpdate(DeserializeInput, SerializeOutput), which more advanced SerializeDeserialize
implementations should override.
Dependencies
Many serializers for complex types will rely on dependent serializers, such as for assembly line-style processing or for handling parts of a greater object. In that case, exceptions thrown by dependent serializers need not be caught: they can simply be re-thrown to the caller.
Additionally, dependent serializers can be relied upon to adhere to contracts or reasonable expectations.
If they do not, an implementation is permitted to throw its own DeveloperMistakeException stating as such.
An example of a reasonable expectation would be assuming that a serializer for Integer (unannotated) can
successfully process the integer 1.
API Note
This class is the closest equivalent to version 1's "ValueSerialiser." Please use
ConfigurationBuilder.addSimpleSerializer(TypeToken, SerializeDeserialize) if you would like a convenient
method to attach an implementation of this class.
-
Method Summary
Modifier and TypeMethodDescription@NonNull LoadResult<@NonNull V> deserialize(@NonNull DeserializeInput deser) Deserializes using the given operable object.default @NonNull LoadResult<@NonNull V> deserializeUpdate(@NonNull DeserializeInput deser, @NonNull SerializeOutput updateTo) Deserializes using the given operable object, and updates the input value if needed.voidserialize(@NonNull V value, @NonNull SerializeOutput ser) Serializes this value.
-
Method Details
-
deserialize
Deserializes using the given operable object.Yields a
Vif successful, or an error result otherwise.Handling Input
The input value is passed as
DeserializeInput.object(). This object is guaranteed to be one of the canonical types according toDataEntry.validateValue(Object).The convenience methods
requireString()andrequireDataTree()onDeserializeInputallow implementors of this method to access these types as preconditions, while rejecting the input if it is of another type.Handling Errors and Imperfection
If the input data is not of proper type or representation, implementations must return an error result. Implementations are recommended to use the factory methods on
DeserializeInputto build and throw error values.Implementations may use a degree of leniency in parsing input values. For example,
"1"(despite being a string) might be treated the same as1by an integer serializer. Leniency is a decision of the implementation.At the same time, data which is truly malformatted -- not recognizable as the output type in any sense -- must be treated by returning an error result. Fallback behavior, like returning a substitute value, is not allowed and should be controlled by other areas of the library.
- Parameters:
deser- the object being deserialized, and its associated context- Returns:
- the deserialized value if successful, or an error result if not
- Throws:
DeveloperMistakeException- if a dependent serializer behaved incorrectly
-
deserializeUpdate
default @NonNull LoadResult<@NonNull V> deserializeUpdate(@NonNull DeserializeInput deser, @NonNull SerializeOutput updateTo) Deserializes using the given operable object, and updates the input value if needed.Please see
deserialize(DeserializeInput)for deserialization-related considerations. Generally, this function and that function should behave identically with respect to the value deserialized; that is, equivalent inputs should produce equivalentLoadResults.Performing Updates
Sometimes types have a canonical representation in human readable configuration files, but they also have alternate (and potentially less efficient) ways of writing them. For example,
"1"is a number for human purposes, but machines would interpret it as a string. This function exists to "correct" such usages by overwriting the preferred representation of the given type.Proceeding with the previous example, an implementation for integers might load both
1and"1"as an integer. But only if"1"was the input, the implementation might want to signal that this value should be updated:if (deser.getValue() instanceof Integer) { // No update necessary return (Integer) deser.getValue(); } return deser.requireString().flatMap((stringVal) -> { int intVal; try { intVal = Integer.parseInt(intVal); } catch (NumberFormatException ignored) { return deser.throwError("Not a valid integer " + stringVal); } // Updating happens here updateTo.outInt(intVal); // Best practice: include a signal that the update occured deser.flagUpdate(KeyPath.empty(), UpdateReason.UPDATED); return LoadResult.of(intVal); });Default Implementation
By default, this method simply calls
deserializeand does not perform an updates. More advancedSerializeDeserializeimplementations should override this function and decide to update if needed.- Parameters:
deser- the object being deserialized, and its associated contextupdateTo- if the input object needs to be updated, this is where the updated value should be placed- Returns:
- the deserialized value if successful, or an error result if not
- Throws:
DeveloperMistakeException- if a dependent serializer behaved incorrectly
-
serialize
Serializes this value.The serialized object must be one of the canonical types, see
DataEntry.validateValue(Object). The implementation MUST output a value before returning; if it does not, aDeveloperMistakeExceptionmay be thrown by another library component.- Parameters:
value- the valueser- where to place the serialized type- Throws:
DeveloperMistakeException- if a dependent serializer behaved incorrectly
-