简体   繁体   English

杰克逊:如果缺少财产怎么办?

[英]Jackson: What happens if a property is missing?

What happens if I annotate a constructor parameter using @JsonProperty but the Json doesn't specify that property. 如果我使用@JsonProperty注释构造函数参数,但Json没有指定该属性,会发生什么情况。 What value does the constructor get? 构造函数得到什么值?

How do I differentiate between a property having a null value versus a property that is not present in the JSON? 如何区分具有空值的属性和JSON中不存在的属性?

Summarizing excellent answers by Programmer Bruce and StaxMan : 总结程序员BruceStaxMan的出色答案:

  1. Missing properties referenced by the constructor are assigned a default value as defined by Java . 构造函数引用的缺少的属性会分配一个Java定义的默认值。

  2. You can use setter methods to differentiate between properties that are implicitly or explicitly set. 您可以使用setter方法来区分隐式或显式设置的属性。 Setter methods are only invoked for properties with explicit values. 只对具有显式值的属性调用设置方法。 Setter methods can keep track of whether a property was explicitly set using a boolean flag (eg isValueSet ). Setter方法可以跟踪是否使用布尔标志(例如isValueSet )显式设置了属性。

What happens if I annotate a constructor parameter using @JsonProperty but the Json doesn't specify that property. 如果我使用@JsonProperty注释构造函数参数,但Json没有指定该属性,会发生什么情况。 What value does the constructor get? 构造函数得到什么值?

For questions such as this, I like to just write a sample program and see what happens. 对于诸如此类的问题,我想编写一个示例程序,然后看看会发生什么。

Following is such a sample program. 以下是这样的示例程序。

import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.map.ObjectMapper;

public class JacksonFoo
{
  public static void main(String[] args) throws Exception
  {
    ObjectMapper mapper = new ObjectMapper();

    // {"name":"Fred","id":42}
    String jsonInput1 = "{\"name\":\"Fred\",\"id\":42}";
    Bar bar1 = mapper.readValue(jsonInput1, Bar.class);
    System.out.println(bar1);
    // output: 
    // Bar: name=Fred, id=42

    // {"name":"James"}
    String jsonInput2 = "{\"name\":\"James\"}";
    Bar bar2 = mapper.readValue(jsonInput2, Bar.class);
    System.out.println(bar2);
    // output:
    // Bar: name=James, id=0

    // {"id":7}
    String jsonInput3 = "{\"id\":7}";
    Bar bar3 = mapper.readValue(jsonInput3, Bar.class);
    System.out.println(bar3);
    // output:
    // Bar: name=null, id=7
  }
}

class Bar
{
  private String name = "BLANK";
  private int id = -1;

  Bar(@JsonProperty("name") String n, @JsonProperty("id") int i)
  {
    name = n;
    id = i;
  }

  @Override
  public String toString()
  {
    return String.format("Bar: name=%s, id=%d", name, id);
  }
}

The result is that the constructor is passed the default value for the data type. 结果是向构造函数传递了数据类型的默认值。

How do I differentiate between a property having a null value versus a property that is not present in the JSON? 如何区分具有空值的属性和JSON中不存在的属性?

One simple approach would be to check for a default value post deserialization processing, since if the element were present in the JSON but had a null value, then the null value would be used to replace any default value given the corresponding Java field. 一种简单的方法是在反序列化处理后检查默认值,因为如果元素存在于JSON中但具有空值,则该空值将用于替换给定相应Java字段的任何默认值。 For example: 例如:

import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;
import org.codehaus.jackson.annotate.JsonMethod;
import org.codehaus.jackson.map.ObjectMapper;

public class JacksonFooToo
{
  public static void main(String[] args) throws Exception
  {
    ObjectMapper mapper = new ObjectMapper().setVisibility(JsonMethod.FIELD, Visibility.ANY);

    // {"name":null,"id":99}
    String jsonInput1 = "{\"name\":null,\"id\":99}";
    BarToo barToo1 = mapper.readValue(jsonInput1, BarToo.class);
    System.out.println(barToo1);
    // output:
    // BarToo: name=null, id=99

    // {"id":99}
    String jsonInput2 = "{\"id\":99}";
    BarToo barToo2 = mapper.readValue(jsonInput2, BarToo.class);
    System.out.println(barToo2);
    // output:
    // BarToo: name=BLANK, id=99

    // Interrogate barToo1 and barToo2 for 
    // the current value of the name field.
    // If it's null, then it was null in the JSON.
    // If it's BLANK, then it was missing in the JSON.
  }
}

class BarToo
{
  String name = "BLANK";
  int id = -1;

  @Override
  public String toString()
  {
    return String.format("BarToo: name=%s, id=%d", name, id);
  }
}

Another approach would be to implement a custom deserializer that checks for the required JSON elements. 另一种方法是实现自定义解串器,以检查所需的JSON元素。 And yet another approach would be to log an enhancement request with the Jackson project at http://jira.codehaus.org/browse/JACKSON 还有另一种方法是在http://jira.codehaus.org/browse/JACKSON的Jackson项目中记录增强请求

In addition to constructor behavior explained in @Programmer_Bruce's answer, one way to differentiate between null value and missing value is to define a setter: setter is only called with explicit null value. 除了@Programmer_Bruce的答案中解释的构造函数行为外,区分空值和缺失值的一种方法是定义一个setter:仅使用显式null值来调用setter。 Custom setter can then set a private boolean flag ("isValueSet" or whatever) if you want to keep track of values set. 然后,如果您想跟踪设置的值,则自定义设置器可以设置一个私有布尔标志(“ isValueSet”或其他)。

Setters have precedence over fields, in case both field and setter exist, so you can "override" behavior this way as well. 如果字段和设置器都存在,则设置器优先于字段,因此您也可以通过这种方式“覆盖”行为。

I'm thinking of using something in the style of an Option class, where a Nothing object would tell me if there is such a value or not. 我正在考虑使用Option类风格的东西,其中Nothing对象会告诉我是否有这样的值。 Has anyone done something like this with Jackson (in Java, not Scala, et al)? 有没有人用Jackson做到过这样的事情(在Java中,不是Scala等人)?

(My answer might be useful to some people finding this thread via google, even if it doesn't answer OPs question) (我的答案可能对某些通过Google找到该主题的人很有用,即使它没有回答OP的问题)
If you are dealing with primitive types which are omittable, and you do not want to use a setter like described in the other answers (for example if you want your field to be final), you can use box objects: 如果要处理的是可忽略的基本类型,并且不想使用其他答案中所述的设置方法(例如,如果希望字段为最终形式),则可以使用框对象:

public class Foo {
    private final int number;
    public Foo(@JsonProperty Integer number) {
        if (number == null) {
            this.number = 42; // some default value
        } else {
            this.number = number;
        }
    }
}

this doesn't work if the JSON actually contains null , but it can be sufficient if you know it will only contain primitives or be absent 如果JSON实际上包含null ,则此方法不起作用,但是如果您知道它将仅包含基元或不存在,就足够了

另一种选择是在反序列化之后手动或通过诸如Java bean验证之类的框架或通过Spring验证支持(如果使用Spring的话)来验证对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 杰克逊在反序列化期间对丢失的财产投掷了NPE - Jackson throws NPE during deserialization on missing property 杰克逊2.5-JsonMappingException:缺少外部类型ID属性 - Jackson 2.5 - JsonMappingException: Missing external type id property 杰克逊序列化,是否有注释指示用于属性的子属性? - jackson serialization, is there an annotation that indicates what sub-properties to use for a property? 杰克逊映射器。 无法解析 [简单类型,类 ] 的子类型:缺少类型 ID 属性“”(对于 POJO 属性“”) - Jackson mapper. Could not resolve subtype of [simple type, class ]: missing type id property '' (for POJO property '') 当我在 java 中声明自定义系统属性时会发生什么? - What happens when I declare a custom system property in java? 杰克逊:阵列中缺少@JsonTypeInfo - Jackson: @JsonTypeInfo missing in Arrays 杰克逊CSV缺少列 - Jackson CSV missing columns 杰克逊错过了价值观 - Jackson missing out values 杰克逊反序列化json字符串,但是bean缺少json字符串的属性/密钥 - Jackson deserialize json string but bean missing json string's property/key Jackson-databind 将缺少属性的 JSON 反序列化为“null”而不是默认值 - Jackson-databind deserializes JSON with missing property as "null" instead of default value
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM