Jackson and Guava data module: ignore missing fields but serialize explicit null values
I am storing test data for a RESTful endpoint in json. I will deserialize the test data into a POJO to pass into REST Assured for testing. Under the hood, REST Assured serializes POJOs using Jackson when building request objects.
I am using a Guava type data module to distinguish between fields that are present in json but are null and those that are not present at all. When json is deserialized to a POJO using jackson with a guava datatype module for optional fields, fields not present in json in the POJO are zero, while those fields that are present in json with a value set explicitly to null are set to Optional.absent ( ).
When a POJO is serialized using Rest Assured (with Jackson under the hood) to create an HTTP Reguest object, I want the "missing" (null in the POJO) fields to be ignored, but those fields that are present but explicitly set to null (Optional. absent () in POJO) for serialization. I cannot use the @JsonInclude (Include.NON_NULL) annotation because it excludes both cases due to the Serializer for Guava data types in the Guava data module handling them. I want to override this behavior while maintaining my ability to use the module. I'm not sure how to do this.
Here's an example of what I'm talking about:
public class Item {
private Optional<Integer> id;
private Optional<String> name;
private Optional<String> description;
}
{ "name":null, "description":"Something" }
The above POJO will be created in this way as soon as the json String descriptor is deserialized:
Item:
id = null
name = Optional.<String>absent()
description = "Something"
When the POJO is serialized back to json, I want the result to be as it is in the test data:
{ "name":null, "description":"Something" }
However, I get the following:
{ "id":null, "name":null, "description":"Something" }
If I use @JsonInclude (Include.NON_NULL) I get this:
{ "description":"Something" }
UPDATE:
So, I basically hacked into the module to do what I wanted. Here are the changes I made:
In GuavaOptionalSerializer
I changed isEmpty(Optional<?> value)
to return true only if the value was null
, not if null
or absent
.
@Override
public boolean isEmpty(Optional<?> value) {
return (value == null);
}
And in GuavaOptionalBeanPropertyWriter
I changed the method serializeAsField
to handle the suppression of null values ββfirst and then process the values null
:
@Override
public void serializeAsField(Object bean, JsonGenerator jgen, SerializerProvider prov) throws Exception
{
// and then see if we must suppress certain values (default, empty)
if (_suppressableValue != null) {
super.serializeAsField(bean, jgen, prov);
return;
}
if (_nullSerializer == null) {
Object value = get(bean);
if (Optional.absent().equals(value)) {
return;
}
}
super.serializeAsField(bean, jgen, prov);
}
Now if I want to include fields absent
(explicitly set to null
) and exclude fields that are simply "missing", I use @JsonInclude(Include.NON_EMPTY) annotation
.
Unfortunately, looking at the source for the serializer , I don't see there is a ready-made way to do what you're looking for. Optional.absent()
just delegates the default processing behavior that will respect the annotation @JsonInclude
.
This Optional<>
makes sense, because the whole motivation is that you shouldn't assign a null
link Optional<>
.
However, you can always write your own serializer to do this for you. The implementation will be similar to the linked one GuavaOptionalSerializer
, but you will need to change this function:
@Override
public void serialize(Optional<?> value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonGenerationException {
if(value.isPresent()){
provider.defaultSerializeValue(value.get(), jgen);
} else{
// provider.defaultSerializeNull(jgen);
// force writing null here instead of using default
}
}