title: Jackson won't serialize null with a custom Serializer
body: <p>I have a custom bean serializer that I'd like to apply, but when I do, Jackson no longer includes null properties.</p>
  <p>The following code reproduces the issue:</p>
  <pre><code>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 {
  
    @Value
    public static class Contact {
      String first;
      String middle;
      String last;
      String email;
    }
    
    
    public static void main(String[] args) throws Exception {
      Contact contact = new Contact(&quot;Bob&quot;, null, &quot;Barker&quot;, null);
      
      ObjectMapper mapper = new ObjectMapper();
      mapper.registerModule(new SimpleModule() {
          @Override public void setupModule(SetupContext context) {
              super.setupModule(context);
              context.addBeanSerializerModifier(new BeanSerializerModifier() {
                  @Override public JsonSerializer&lt;?&gt; modifySerializer(SerializationConfig config, BeanDescription desc, JsonSerializer&lt;?&gt; serializer) {
  //                  return serializer;
                    return new JsonSerializer&lt;Object&gt;() {
                      @Override public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
                        ((JsonSerializer&lt;Object&gt;) serializer).serialize(value, gen, serializers);
                      }};
                  }
              });
          }
      });
      
      
      System.out.println(
          mapper.writerWithDefaultPrettyPrinter().writeValueAsString(contact)
      );
      
    }
  }
  </code></pre>
  <p>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:</p>
  <blockquote>
  <p>{   &quot;first&quot; : &quot;Bob&quot;,   &quot;last&quot; : &quot;Barker&quot; }</p>
  </blockquote>
  <p>If you comment out the <code>return new JsonSerializer&lt;Object&gt;() {...</code> and return the passed in serializer as is <code>return serializer;</code>, then Jackson serializes the null properties:</p>
  <blockquote>
  <p>{   &quot;first&quot; : &quot;Bob&quot;,   &quot;middle&quot; : null,   &quot;last&quot; : &quot;Barker&quot;,   &quot;email&quot;
  : null }</p>
  </blockquote>
  <hr />
  <p>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 <code>Include.ALWAYS</code> on serialization, with no luck.</p>
  <p>My only lead is a comment in the JavaDoc for JsonSerializer:</p>
  <blockquote>
  <p>NOTE: various <code>serialize</code> methods are never (to be) called
  with null values -- caller <b>must</b> handle null values, usually
  by calling {@link SerializerProvider#findNullValueSerializer} to obtain
  serializer to use.<br />
  This also means that custom serializers cannot be directly used to change<br />
  the output to produce when serializing null values.</p>
  </blockquote>
  <p>I am using Jackson version 2.11.2.</p>
  <hr />
  <p>My question is:  <strong>How can I write a custom serializer and have Jackson respect its usual Include directives with regard to null property serialization?</strong></p>
  <p>Context Info:  My actual custom serializer's job is to conditionally hide properties from serialization.  I have a custom annotation, <code>@JsonAuth</code> that is meta-annotated with <code>@JacksonAnnotationsInside @JsonInclude(Include.NON_EMPTY)</code> which my custom serializer (a <code>ContextualSerializer</code>) looks for in an overriden <code>isEmpty</code> method and returns <code>true</code> (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.</p>
  <hr />
  <p>Update:  <strong>Jackson's <code>BeanPropertyWriter.serializeAsField(...)</code> method will completely ignore any custom serializer assigned to the property if the value is null.</strong></p>
  <p>I was able to override this behavior by writing a small extension to the class, which allowed my &quot;isAuthorized&quot; logic to preempt the null check:</p>
  <pre><code>  public class JsonAuthPropertyWriter extends BeanPropertyWriter {
     
      private final Predicate&lt;Object&gt; authFilter; 
      
      private JsonAuthPropertyWriter(BeanPropertyWriter delegate, Predicate&lt;Object&gt; authFilter) {
        super(delegate);
        this.authFilter = authFilter;
        // set null serializer or authorized null values disappear
        super.assignNullSerializer(NullSerializer.instance);
      }
      
      @Override
      public void serializeAsField(
          Object bean,
          JsonGenerator gen,
          SerializerProvider prov) throws Exception {
        boolean authorized = authFilter.test(bean);
        if (!authorized) return;
        super.serializeAsField(bean, gen, prov);
      }
    }
  </code></pre>
  <p>And I injected these custom BeanPropertyWriters using a <code>BeanSerializerModifier</code>:</p>
  <pre><code>  private static class JsonAuthBeanSerializerModifier extends BeanSerializerModifier {
      
      @Override
      public List&lt;BeanPropertyWriter&gt; changeProperties(
          SerializationConfig config,
          BeanDescription beanDesc, 
          List&lt;BeanPropertyWriter&gt; beanProperties
          ) {
        
        for (int i = 0; i &lt; beanProperties.size(); i++) {
          BeanPropertyWriter beanPropertyWriter = beanProperties.get(i);
          JsonAuth jsonAuth = beanPropertyWriter.findAnnotation(JsonAuth.class);
          if (jsonAuth != null) {
            Predicate&lt;Object&gt; authPredicate = ...
            beanProperties.set(i, new JsonAuthPropertyWriter(beanPropertyWriter, authPredicate));
          }
        }
        return beanProperties;
      }
      
    }
  </code></pre>