Java 如何使用Jackson反序列化空类型JSON字段

Java 如何使用Jackson反序列化空类型JSON字段,java,json,null,jackson,deserialization,Java,Json,Null,Jackson,Deserialization,我正在开发一个补丁API。如果字段作为JSONnull值发送,我需要将它们保存为null。但是,我无法区分它们是作为null发送还是从未发送 { "max_amount": null } 双倍最大金额; 我有Double,Integer,Date等字段。当它们真正作为null发送时,我可以将它们反序列化为Double.NAN,Integer.MIN\u值,以了解它们是否作为null发送。但是当字段为null时,反序列化程序不工作。当然,它是一个发送“-1”的选项,或者是一个不可能

我正在开发一个补丁API。如果字段作为
JSON
null
值发送,我需要将它们保存为
null
。但是,我无法区分它们是作为
null
发送还是从未发送

{
      "max_amount": null
}
双倍最大金额;

我有
Double
Integer
Date
等字段。当它们真正作为
null
发送时,我可以将它们反序列化为
Double.NAN
Integer.MIN\u值
,以了解它们是否作为
null
发送。但是当字段为
null
时,反序列化程序不工作。当然,它是一个发送“-1”的选项,或者是一个不可能定义
null
的值,但我不喜欢这种方法。我必须同意客户的所有类型。在这种情况下,最好的方法是什么

在这种情况下,您应该定义
POJO
类,并将属性设置为预定义的
未定义的数据。例如,对于
Integer
属性,如果从业务角度来看不允许使用负数,则它可以是
-1
。然后,当
JSON
反序列化为
POJO
时,属性设置为
null
覆盖默认值,您将知道它已发送。应该有3种选择:

  • JSON中的常规值
    -正确反序列化为
    POJO中的值
  • JSON中的
    null
    值-反序列化为
    POJO中的
    null
  • 不可用对
    键值
    -未覆盖
    POJO
    中的默认值
  • 下面的示例使用版本
    2.9.9
    中的
    Jackson

    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 +
                    '}';
        }
    }
    
    以上代码打印:

    {"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}
    

    当然,您应该选择默认值,这样可以最大限度地减少冲突的可能性,客户机意外发送的值被您的
    API处理为
    undefined

    ,感谢您的评论和努力。然而,我们找到了一个更好的解决方案来摆脱默认值。我们定义了一个isMaxAmountSet布尔值,并在maxAmount的setter处将其设置为true。所以,我们可以区分这个值是否在请求体中发送。