杰克逊:如果财产遗失会怎样?

时间:2011-11-30 04:03:28

标签: java jackson

如果我使用@JsonProperty注释构造函数参数但Json没有指定该属性会发生什么。构造函数得到什么价值?

如何区分具有空值的属性与JSON中不存在的属性?

6 个答案:

答案 0 :(得分:44)

总结Programmer BruceStaxMan的优秀答案:

  1. 构造函数引用的缺失属性被分配了默认值as defined by Java

  2. 您可以使用setter方法来区分隐式或显式设置的属性。仅对具有显式值的属性调用Setter方法。 Setter方法可以跟踪是否使用布尔标志显式设置属性(例如isValueSet)。

答案 1 :(得分:34)

  

如果我使用@JsonProperty注释构造函数参数但Json没有指定该属性会发生什么。构造函数得到什么价值?

对于这样的问题,我想写一个示例程序,看看会发生什么。

以下是这样的示例程序。

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);
  }
}

结果是构造函数传递了数据类型的默认值。

  

如何区分具有空值的属性与JSON中不存在的属性?

一种简单的方法是在反序列化处理后检查默认值,因为如果该元素存在于JSON中但具有空值,则null值将用于替换给定相应Java字段的任何默认值。例如:

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);
  }
}

另一种方法是实现一个自定义反序列化器,用于检查所需的JSON元素。另一种方法是在http://jira.codehaus.org/browse/JACKSON

处记录杰克逊项目的增强请求

答案 2 :(得分:11)

除了@ Programmer_Bruce的答案中解释的构造函数行为之外,区分空值和缺失值的一种方法是定义一个setter:setter仅使用显式null值调用。 如果要跟踪设置的值,自定义setter可以设置一个私有布尔标志(“isValueSet”或其他)。

如果字段和setter都存在,则setter优先于字段,因此您也可以通过这种方式“覆盖”行为。

答案 3 :(得分:3)

我正在考虑使用Option类风格的东西,其中Nothing对象会告诉我是否有这样的值。有没有人用杰克逊(Java,而不是Scala等人)做过这样的事情?

答案 4 :(得分:0)

(我的回答可能对某些人通过谷歌找到这个帖子很有用,即使它没有回答OP问题)
如果您正在处理可省略的原始类型,并且您不想使用其他答案中描述的setter(例如,如果您希望字段为final),则可以使用box对象:

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;
        }
    }
}

如果JSON实际上包含null,则不起作用,但如果您知道它只包含基元或不存在则可能就足够了

答案 5 :(得分:0)

another option is to validate the object after deserialization either manually or via frameworks such java bean validation or, if you are using spring, the spring validation support.