Jackson won’t serialize null with a custom Serializer

I have a custom bean serializer that I'd like to apply, but when I do, Jackson no longer includes null properties.

The following code reproduces the issue:

import java.io.IOException;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import lombok.Value;

public class Test {

  public static class Contact {
    String first;
    String middle;
    String last;
    String email;
  public static void main(String[] args) throws Exception {
    Contact contact = new Contact("Bob", null, "Barker", null);
    ObjectMapper mapper = new ObjectMapper();
    mapper.registerModule(new SimpleModule() {
        @Override public void setupModule(SetupContext context) {
            context.addBeanSerializerModifier(new BeanSerializerModifier() {
                @Override public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription desc, JsonSerializer<?> serializer) {
//                  return serializer;
                  return new JsonSerializer<Object>() {
                    @Override public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
                      ((JsonSerializer<Object>) serializer).serialize(value, gen, serializers);

The above code does nothing other that register a 'custom' serializer (that just delegates back to the original serializer), yet it produces JSON without the null properties:

{ "first" : "Bob", "last" : "Barker" }

If you comment out the return new JsonSerializer<Object>() {... and return the passed in serializer as is return serializer;, then Jackson serializes the null properties:

{ "first" : "Bob", "middle" : null, "last" : "Barker", "email" : null }

I have read over many seemingly related SO articles, but none have led me to a solution yet. I've tried explicitly setting the mapper to Include.ALWAYS on serialization, with no luck.

My only lead is a comment in the JavaDoc for JsonSerializer:

NOTE: various serialize methods are never (to be) called with null values -- caller must handle null values, usually by calling {@link SerializerProvider#findNullValueSerializer} to obtain serializer to use.
This also means that custom serializers cannot be directly used to change
the output to produce when serializing null values.

I am using Jackson version 2.11.2.

My question is: How can I write a custom serializer and have Jackson respect its usual Include directives with regard to null property serialization?

Context Info: My actual custom serializer's job is to conditionally hide properties from serialization. I have a custom annotation, @JsonAuth that is meta-annotated with @JacksonAnnotationsInside @JsonInclude(Include.NON_EMPTY) which my custom serializer (a ContextualSerializer) looks for in an overriden isEmpty method and returns true (treat as empty) if authorization is lacking. The end result is that I have an annotation that can be applied to properties which will hide the property from serialization if the client is not authorized. Except ... usage of the custom serializer has the unintended side effect of dropping all null properties.

Read more here: https://stackoverflow.com/questions/64923635/jackson-wont-serialize-null-with-a-custom-serializer

Content Attribution

This content was originally published by allenru at Recent Questions - Stack Overflow, and is syndicated here via their RSS feed. You can read the original post over there.

%d bloggers like this: