5

According to this answer: https://stackoverflow.com/a/43342675/5810648

I wrote such serializer:

public class CustomSerializer extends StdSerializer<Double> implements ContextualSerializer {

    private final NAifNull annotation;

    public CustomSerializer() {
        super(Double.class);
        this.annotation = null;
    }

    public CustomSerializer(NAifNull annotation) {
        super(Double.class);
        this.annotation = annotation;
    }

    @Override
    public void serialize(Double value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        if (annotation != null && value == null) {
            gen.writeString("N/A");
        } else {
            gen.writeNumber(value);
        }
    }

    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) {
        NAifNull annotation = property.getAnnotation(NAifNull.class);
        return new CustomSerializer(annotation);
    }
}

Witch supposed to write string "N/A" if the annotation is present and field is null. But method serialize is called only for not null fields.

Also, I have tried to call setNullValueSerializer:

@Override
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) {
    NAifNull annotation = property.getAnnotation(NAifNull.class);
    prov.setNullValueSerializer(new CustomNullSerializer(annotation));
    return new CustomSerializer(annotation);
}

With such implementation:

private static class CustomNullSerializer extends JsonSerializer<Object> {
    private final NAifNull annotation;

    public CustomNullSerializer(NAifNull annotation) {
        this.annotation = annotation;
    }

    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        if (annotation != null) {
            gen.writeString("N/A");
        } else {
            gen.writeNull();
        }
    }
}

But no result.

How to handle null fields in such way?

Update

According to discussion: https://github.com/FasterXML/jackson-databind/issues/2057

prov.setNullValueSerializer(new CustomNullSerializer(annotation));

Is not supposed to be called from CreateContextual method.

Ihor Rybak
  • 3,091
  • 2
  • 25
  • 32

2 Answers2

10

Use a BeanSerializerModifier to customize the null serializer for a particular property:

public class CustomBeanSerializerModifier extends BeanSerializerModifier {

    @Override
    public List<BeanPropertyWriter> changeProperties(SerializationConfig config, 
           BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {

        for (BeanPropertyWriter beanProperty : beanProperties) {
            if (beanProperty.getAnnotation(NAifNull.class) != null) {
                beanProperty.assignNullSerializer(new CustomNullSerializer());
            }
        }

        return beanProperties;
    }
}

Where @NAifNull and CustomNullSerializer are define as follows:

public class CustomNullSerializer extends JsonSerializer<Object> {

    @Override
    public void serialize(Object value, JsonGenerator jgen, 
           SerializerProvider provider) throws IOException {
        jgen.writeString("N/A");
    }
}
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@interface NAifNull {

}

Then use it as follows:

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new SimpleModule() {

    @Override
    public void setupModule(SetupContext context) {
        super.setupModule(context);
        context.addBeanSerializerModifier(new CustomBeanSerializerModifier());
    }
});
cassiomolin
  • 124,154
  • 35
  • 280
  • 359
  • 1
    I managed to use this solution to serialize null values to a default value **depending on the actual type** of the null value, e.g. null String => `""`, null Number => `"0"`, as standard serializer `serialize()` callback is never called by null values. I just did: `new SimpleModule().setSerializerModifier(...)` for the setup. Thx! :) – Gerard Bosch Dec 31 '20 at 10:28
0

If I understood you correctly, you want to write "N/A" to generated JSON, if the value is null.

Jackson docs states that value cannot be null. This is because the type parameter is Class object, which is constructed automatically by JVM.

As per this article, I think you could handle null fields with something like

public class CustomNullSerializer extends StdSerializer<Object> {

   public CustomNullSerializer() {
        this(null);
   }

   public CustomNullSerializer(Class<Object> t) {
        super(t);
   }

   @Override
   public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeString("N/A");
   }
}

And then use it with

prov.setNullValueSerializer(new CustomNullSerializer());

Thought I didn't try this myself, but I hope it helps.

UPDATE

Okey, now I had time to try this myself. I got it working with

ObjectMapper mapper...
mapper.getSerializerProvider().setNullValueSerializer(new CustomNullSerializer());