Implementation

Serializers and how to implement your own classes.

Serializers are processors which handle serialization/deserialization of custom classes (not natively supported Java types outside of the YAML spec).

All serializers follow this common pattern:

  • Deserialization: Map -> Object of custom type

  • Serialization: Object of custom type -> Map

BoostedYAML uses StandardSerializer.getDefault() by default, but you can change it via the settings.

StandardSerializer

Type key

Type key defines key, at which information about your class will be stored in the Map (when serialized, see "Serialization" at the top).

StandardSerializer.getDefault() uses ==, which means in serialized form, your object at route "x" could look like this:

x:
  ==: me.user.project.Person
  name: Martin
  age: 20

To use custom keys, create your own instance of StandardSerializer, e.g.

new StandardSerializer("_");

Registering your class

To make your type recognizable by that instance of StandardSerializer, you must register it:

<T> StandardSerializer#register(@NotNull Class<T> clazz, @NotNull TypeAdapter<T> adapter)

The serializer now knows that exact (no subtypes) type thanks to the adapter provided. TypeAdapter is called to serialize/deserialize the type. Now you can freely set/get your custom type from sections.

You can also register an alias for your custom type using this method. Aliases are commonly used to maintain compatibility even after the class' canonical name has been changed (e.g. the class was moved to other package).

Serializers are instantiable.

Types are registered to that instance of StandardSerializer; won't be available for another instance of the serializer.

Example

Let's suppose we have the following class:

public class Person {
    
    private String name;
    private int age;
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public String getName() {
        return name;
    }
    
    public int getAge() {
        return age;
    }

}

Assuming we would like to use both the name and age field, our adapter could look like this:

TypeAdapter<Person> adapter = new TypeAdapter<Person>() {
    
    @NotNull
    Map<Object, Object> serialize(@NotNull Person object) {
        Map<Object, Object> map = new HashMap<>();
        map.put("name", object.getName());
        map.put("age", object.getAge());
        return map;
    }
    
    @Nullable
    T deserialize(@NotNull Map<Object, Object> map) {
        String name = map.get("name");
        int age = (int) map.get("age");
        return new Person(name, age);
    }
    
}

If needed, convert Map<Object, Object> to Map<String, Object> using toStringKeyedMap(@NotNull Map<?, ?> map) method.

If we left the serializer on default (that means, StandardSerializer.getDefault()), we would need to register the type to that serializer:

StandardSerializer.getDefault().register(Person.class, adapter);

We're done! 🎉

Custom serializers

If you'd like to create and use a custom serializer, you would need to implement YamlSerializer class. Please look at the class documenation for more information.

Last updated