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

.

+3


source to share


1 answer


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
    }
}

      

+2


source







All Articles