-
Notifications
You must be signed in to change notification settings - Fork 3
Custom Serializers and Deserializers
Since 0.8.7
Custom serializers allow adjusting the serialization of specific types in case the default is not suitable.
Custom serializers must implement the ValueSerializer<T> interface which has only one method - serialize. This method takes two arguments:
- The instance to be serialized
- a
SerializationContextinstance representing the current serialization context
and returns a JSONNode representing the serialized value. The serialization context contains some important contextual data, like the field being serialized (if available) and the IRI of the property that this attribute represents (again, if available). Note that, for example, if the value being serialized is an element of a collection, the field and the attribute IRI may not be available.
Here's a simplistic example that demonstrates how custom serializer for LocalDate can be implemented to serialize instances as ISO-formatted string node.
public class LocalDateSerializer implements ValueSerializer<LocalDate> {
@Override
public JsonNode serialize(LocalDate value, SerializationContext<LocalDate> ctx) {
return JsonNodeFactory.createLiteralNode(ctx.getAttributeId(), value.toString());
}
}Of course, such a simple serializer could have been declared as a lambda.
Serializer instances are registered on the JsonLdSerializer for specific types. So, for example:
sut = JsonLdSerializer.createContextBuildingJsonLdSerializer(new JacksonJsonWriter());
sut.registerSerializer(LocalDate.class, new LocalDateSerializer());JB4JSON-LD will use the same instance, so they should have no state.
Note that in 0.14.0 the library was rewritten to use the Jakarta JSON API. With that, the ValueDeserializer API has changed as well.
Custom deserializers allow adjusting the deserialization of specific types in case the default is not suitable.
Custom deserializers must implement the ValueDeserializer<T> interface which has only one method - deserialize. This method takes two arguments:
- The JSON-LD node to be deserialized. It is represented by the Jakarta JSON
JsonValueinterface, but given the nature of data (using expanded JSON-LD), it will more likely beJsonObject. - a
DeserializationContextinstance representing the current deserialization context.
The method should return the deserialized value.
Note that since the deserialization first expands the JSON-LD input, the JSON-LD node passed to the custom deserializer will be expanded as well. This in particular means that the values of the map will be always lists (unless they represent the @id attribute, which is always singular).
A simplistic example of a custom deserializer (taken from the tests) may look as follows:
public class EmployeeDeserializer implements ValueDeserializer<Employee> {
@Override
public Employee deserialize(JsonValue jsonNode, DeserializationContext<Employee> ctx) {
final Employee result = new Employee();
result.setUri(URI.create(jsonNode.asJsonObject().getString(JsonLd.ID)));
final JsonArray firstName = jsonNode.asJsonObject().get(Vocabulary.FIRST_NAME).asJsonArray();
result.setFirstName(firstName.get(0).asJsonObject().getString(JsonLd.VALUE));
final JsonArray lastName = jsonNode.asJsonObject().get(Vocabulary.LAST_NAME).asJsonArray();
result.setLastName(lastName.get(0).asJsonObject().getString(JsonLd.VALUE));
return result;
}
}Deserializer instances are registered on the JsonLdDeserializer for specific types. So, for example:
final JsonLdDeserializer deserializer = JsonLdDeserializer.createExpandedDeserializer(config);
deserializer.registerDeserializer(Employee.class, new EmployeeDeserializer());JB4JSON-LD will use the same instance, so they should have no state.