Джексон: что произойдет, если свойство отсутствует?


что произойдет, если я аннотирую параметр конструктора с помощью @JsonProperty но Json не указывает это свойство. Какое значение получает конструктор?

Как я могу отличить свойство, имеющее нулевое значение, от свойства, которое отсутствует в JSON?

6 51

6 ответов:

подведение итогов отличные ответы на Программист Брюс и StaxMan:

  1. свойства, на которые ссылается конструктор присваивается значение по умолчанию как определено Java.

  2. вы можете использовать методы setter для различения свойств, которые неявно или явно заданы. Сеттер методы вызываются только для свойств с явными значениями. Методы сеттера могут отслеживать ли свойство было явно задано с помощью логического флага (например,isValueSet).

что произойдет, если я аннотирую параметр конструктора с помощью @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, но имел нулевое значение, то нулевое значение будет использоваться для замены любого значения по умолчанию, заданного соответствующим полем 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

в дополнение к поведению конструктора, описанному в ответе @Programmer_Bruce, один из способов различить нулевое значение и отсутствующее значение-определить сеттер: сеттер вызывается только с явным нулевым значением. Пользовательский сеттер может затем установить частный логический флаг ("isValueSet" или что-то еще), если вы хотите отслеживать набор значений.

сеттеры имеют приоритет над полями, если существуют как поле, так и сеттер, поэтому вы можете "переопределить" поведение таким образом.

Я думаю использовать что-то в стиле класса Option, где объект Nothing скажет мне, есть ли такое значение или нет. Кто-нибудь делал что-то подобное с Джексоном (на Java, а не на Scala и др.)?

(мой ответ может быть полезен некоторым людям, которые находят эту тему через google, даже если он не отвечает на вопрос OPs)
Если вы имеете дело с примитивными типами, которые опущены, и вы не хотите использовать сеттер, как описано в других ответах (например, если вы хотите, чтобы ваше поле было окончательным), вы можете использовать объекты 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, но этого может быть достаточно, если вы знаете, что он будет содержать только примитивы или отсутствует

другой вариант:проверка объект после десериализации либо вручную, либо через фреймворки, такие как проверка Java bean, либо, если вы используете spring, поддержка проверки spring.