Interface SerializeDeserialize<V>

Type Parameters:
V - the deserialized type

public interface SerializeDeserialize<V>
A serializer.

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 Details

    • deserialize

      @NonNull LoadResult<@NonNull V> deserialize(@NonNull DeserializeInput deser)
      Deserializes using the given operable object.

      Yields a V if 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 to DataEntry.validateValue(Object).

      The convenience methods requireString() and requireDataTree() on DeserializeInput allow 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 DeserializeInput to 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 as 1 by 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 equivalent LoadResults.

      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 1 and "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 deserialize and does not perform an updates. More advanced SerializeDeserialize implementations should override this function and decide to update if needed.

      Parameters:
      deser - the object being deserialized, and its associated context
      updateTo - 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

      void serialize(@NonNull V value, @NonNull SerializeOutput ser)
      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, a DeveloperMistakeException may be thrown by another library component.

      Parameters:
      value - the value
      ser - where to place the serialized type
      Throws:
      DeveloperMistakeException - if a dependent serializer behaved incorrectly