简体   繁体   中英

Configure Jackson to honor SerializationInclusion configuration for custom Serializer classes

I'm having a rather interesting problem attempting to get Jackson to properly remove null fields from resulting JSON when they have been created by a custom serializer class. I've searched pretty thoroughly for information regarding Serializer and the SerializationInclusion configuration, but I haven't found anything that seems to explain what I'm seeing.

I have a Jackson object mapper configured and autowired in via Spring. The object mapper configuration and POJOs (edited for brevity) look more or less like the code below.

For some reason, when I call our REST endpoint to get a Bar object back that contains the above example values I see the following behavior:

  • The SerializationInclusion setting is being applied to all properties that are empty or null on their own (name, aList, objId).
  • The SerializationInclusion setting is NOT being applied to any properties that are set to null by a custom Serializer class, and we get back JSON that has a null value present.

My thought here is that the Serializer logic gets called AFTER the Jackson has already removed all null and empty values from the JSON, and therefore the "foo" property is properly set to null, but is not removed because the inclusion logic has already executed.

Does anyone have any thoughts about what might be going on here? Is this a quirk in how Jackson-databind library is implemented in version 2.2.2?


Jackson Config -

@Bean
public JacksonObjectMapper jacksonMapper() {
    final JacksonObjectMapper mapper = new JacksonObjectMapper();

    mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    mapper.enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY);
    mapper.enable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS);
    mapper.registerModule(agJacksonModule());

    return mapper;
}

@Bean
public SimpleModule agJacksonModule() {
    final SimpleModule module = new SimpleModule();

    module.addSerializer(Foo.class, new FooSerializer());

    return module;
}

Custom Serializer -

public class FooSerializer extends JsonSerializer<Foo> {

@Override
public void serialize(Sponsor sponsor, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
        throws IOException {

    // write null value for sponsor json property, if sponsor object has all empty or null fields
    if(sponsor == null || isObjectEmpty(sponsor)) {
        jsonGenerator.writeNull();
        return;
    }

    // write out object
    jsonGenerator.writeStartObject();
    jsonGenerator.writeStringField("imgUrl", sponsor.getImgUrl());
    jsonGenerator.writeStringField("clickUrl", sponsor.getClickUrl());
    jsonGenerator.writeStringField("sponsorName", sponsor.getSponsorName());
    jsonGenerator.writeStringField("sponsorText", sponsor.getSponsorText());
    jsonGenerator.writeEndObject();

}

private boolean isObjectEmpty(Sponsor sponsor) {
    return Strings.isNullOrEmpty(sponsor.getClickUrl())
            && Strings.isNullOrEmpty(sponsor.getImgUrl())
            && Strings.isNullOrEmpty(sponsor.getSponsorName())
            && Strings.isNullOrEmpty(sponsor.getSponsorText());
}

}

The object model looks something like this (again edited for brevity, sample values are set on the class members as example data):

Bar POJO -

public abstract class Bar {

    protected Foo foo = aFoo;
    protected String name = "";
    protected ArrayList aList = Lists.newArrayList();
    protected String objId = null;

    // some getters and setters for the above properties 
}

Foo POJO -

public abstract class Foo {

    protected String aString = "";
    protected String bString = "";
    protected String cString = "";
    protected String dString = "";

    // some getters and setters for the above properties
}

Override and implement the isEmpty method of JsonSerializer to achieve what you want.

For custom definition of what emptymeans, your JsonSerializer implementation needs to override this method:

public boolean isEmpty(SerializerProvider provider, T value);

Note that it is the caller that has to handle filtering as it writes field name; serializer will only be called in case actual serialization is needed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM