How to deserialize null type JSON fields with Jackson

Sercan :

I'm developing a PATCH API. If the fields are sent as JSON null value I need to save them as null. However I can't distinguish if they're sent as null or never sent.

{
      "max_amount": null
}
Double maxAmount;

I have Double, Integer, Date etc. fields. I can deserialize them to Double.NAN, Integer.MIN_VALUE when they're really sent as null to understand if they're sent as null. But Deserializers don't work when the field is null. Of course it's an option to send "-1" or an impossible value to define null but I didn't like this approach. I will have to agree with the clients for all types. What's the best approach in this case?

Michał Ziober :

In cases like this you should define POJO class with properties set to predefined undefined like data. For example, for Integer property if negative numbers are not allowed from business point of view, it could be -1. Then, when JSON is deserialised to POJO properties set to null override default values and you will know it was sent. There should be 3 options:

  1. Regular value in JSON - properly deserialised to a value in POJO
  2. null value in JSON - deserialised to null in POJO
  3. Not available pair key-value - default value in POJO is not overridden.

Below example uses Jackson in version 2.9.9:

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

import java.time.LocalDateTime;

public class JsonApp {

    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new JavaTimeModule());

        String[] jsons = {
                "{\"number\":1,\"date\":\"2019-01-01T22:23:11\",\"max_amount\":4.9}",
                "{\"number\":null,\"date\":null,\"max_amount\":null}",
                "{}",
                "{\"number\":1}",
                "{\"date\":\"2019-01-01T22:23:11\"}",
                "{\"max_amount\":4.9}",
                "{\"number\":1,\"date\":null,\"max_amount\":null}"
        };
        for (String json : jsons) {
            System.out.println(json + " => " + mapper.readValue(json, Pojo.class));
        }
    }
}

class Pojo {

    private static final LocalDateTime NULL_DATE = LocalDateTime.of(1900, 1, 1, 12, 13);

    @JsonProperty("max_amount")
    private Double maxAmount = Double.MIN_VALUE;
    private Integer number = Integer.MIN_VALUE;

    @JsonFormat(shape = JsonFormat.Shape.STRING)
    private LocalDateTime date = NULL_DATE;

    public Double getMaxAmount() {
        return maxAmount;
    }

    public void setMaxAmount(Double maxAmount) {
        this.maxAmount = maxAmount;
    }

    public Integer getNumber() {
        return number;
    }

    public void setNumber(Integer number) {
        this.number = number;
    }

    public LocalDateTime getDate() {
        return date;
    }

    public void setDate(LocalDateTime date) {
        this.date = date;
    }

    @Override
    public String toString() {
        return "{" +
                "number=" + number +
                ", date=" + date +
                ", maxAmount=" + maxAmount +
                '}';
    }
}

Above code prints:

{"number":1,"date":"2019-01-01T22:23:11","max_amount":4.9} => {number=1, date=2019-01-01T22:23:11, maxAmount=4.9}
{"number":null,"date":null,"max_amount":null} => {number=null, date=null, maxAmount=null}
{} => {number=-2147483648, date=1900-01-01T12:13, maxAmount=4.9E-324}
{"number":1} => {number=1, date=1900-01-01T12:13, maxAmount=4.9E-324}
{"date":"2019-01-01T22:23:11"} => {number=-2147483648, date=2019-01-01T22:23:11, maxAmount=4.9E-324}
{"max_amount":4.9} => {number=-2147483648, date=1900-01-01T12:13, maxAmount=4.9}
{"number":1,"date":null,"max_amount":null} => {number=1, date=null, maxAmount=null}

Of course, you should pick default values in the way it will minimise possibility of collision that client by accident send value treated as undefined by your API.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

How does Jackson deserialize json into a generic type?

Deserialize json using jackson to correct subclass type

Is Jackson really unable to deserialize json into a generic type?

How do I configure Jackson ObjectMapper to deserialize all fields of type Foo into instances of SubclassOfFoo?

How to deserialize a generic type with ObjectMapper Jackson

How to deserialize JSON object into Kotlin Pair with Jackson?

Jackson - How to process (deserialize) nested JSON?

Jackson: How to deserialize json with shorthand property value

Jackson deserialize based on type

How to deserialize interface fields using Jackson's objectMapper?

Jackson deserialize extra fields as map

Jackson unable to deserialize the fields with hyphen

Deserialize JSON with Jackson and @JsonCreator

Jackson to deserialize JSON with generics

Deserialize json with same key but different type in android using Jackson

How to deserialize fields from incomplete JSON in .net?

Jackson and Iterable: how to deserialize

How to deserialize a Map<?, ?> with Jackson?

How to deserialize with jackson objectmapper

How to replace null fields (nested at all levels) from JSON response using Jackson ObjectMapper serialization?

Null id property when deserialize json with jackson and Jackson2HalModule of Spring Hateoas

JSON deserialize , Error : null to value type, how to know exact property causing error?

How to use jackson with lombok Builder to deserialize a json-array?

How do I deserialize JSON into a List<SomeType> with Kotlin + Jackson

How to serialize and deserialize Java Enums as JSON objects with Jackson

How to deserialize a JSON to an object ignoring a key using Jackson?

How deserialize JSON object from HttpResponse using Jackson annotations?

How to deserialize a JSON array to a singly linked list by using Jackson

How do I use Jackson Databind to deserialize the following JSON?