Jackson unwrapping of null value objects

Let's say I have Description value object:

@JsonInclude(value = JsonInclude.Include.ALWAYS)
public class Description {
    @Column(name = "DESCRIPTION")
    private final String description;
}

and Product entity:

@Entity
public class Product extends AbstractEntity<Long> {

    @JsonUnwrapped
    private final Description description;   
}

I created custom serializer for Description:

static class DescriptionSerializer extends StdSerializer<Description> {
    DescriptionSerializer() {
        super(Description.class);
    }

    @Override
    public void serialize(Description value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
        if (value != null) {
            jgen.writeString(value.getDescription());
        } else {
            jgen.writeNull();
        }
    }
}

When I create:

Product product = new Product(new Description("description"));

and serialize it:

String result = mapper.writeValueAsString(spec);

it returns JSON: {"description":"description"}

When I create:

Product product = new Product(null);

it returns {},

but I would expect {"description":null}

If I remove @JsonUnwrapped, it works as I'd expect, but for non-null Description, it would create nested object

Is there a way to keep unwrapping for fields with null value objects in a similar way how it is done for built-in Java types?

1 answer

  • answered 2018-01-11 17:18 rascio

    To have what you want you should try with:

    Product p = new Product(new Description(null));
    

    In the json

    {"description":"description"}
    

    the Description, as a container of other fields exists, what is null is the value of the description field inside the Description object.

    The two kind of serializations have different meaning.

    To easily manage it in your code you can have a class like:

    public class Product {
        private Description description;
    
        public Product(Description d) {
            this.description = d;
        }
    
        public Product() {
            this(new Description()); //all fields are null
        }
    
        public Product(String description) {
             return new Product(new Description(description));
        }
    }
    

    The last two constructor I would prefer as a factory methods, but it is just matter of code style.