Сериализация Джексона, выводящая две строки json для одной переменной Java

#java #json #jackson #lombok

#java #json #Джексон #ломбок

Вопрос:

У меня возникла странная проблема, поскольку я переношу код с Java 8 и Sprint Boot 1.X на 11 и 2.X. Ранее я обнаружил, что Джексон сериализует private boolean isAvailable оба available: false и isAvailable: false . Чтобы добавить больше путаницы, Lombok готов к работе, поэтому у меня нет видимости на получателе, и если это вызывает конфликт. Ниже приведен код класса Java:

 @Data
public class Availability{

    @JsonProperty("isAvailable")
    private boolean isAvailable;

}
  

И повторный запуск JSON из Jackson Object mapper был:

 "Availability" : [{
          "isAvailable" : false,
          "available" : false }]
  

Это было с Jackson 2.8. Теперь с Jackson 2.10 я получаю isAvailable: false только в качестве выходных данных в JSON из ObjectMapper.

 "Availability" : [{
          "isAvailable" : false }]
  

Для меня имеет смысл, что оно должно соответствовать только имени переменной Java, но контракт, к сожалению, имеет обе версии, и я не хочу менять контракт. Некоторые используют is, а некоторые нет. Я знаю, что возможен пользовательский сериализатор, но не уверен, как это сделать и нужно ли это.

Ответ №1:

Это lombok поле, взаимодействующее.

Давайте возьмем этот гипотетический класс (здесь вообще не задействован ломбок или, если уж на то пошло, Джексон):

 class Example {
    public boolean isAvailable() {
        return true;
    }
}
  

Согласно спецификации beanspec, Example класс имеет единственное доступное только для чтения свойство bean типа boolean, вызываемое available . Это потому, что любой метод без аргументов, который возвращает логическое значение и начинается с is (а затем с заглавной буквы), считается средством доступа, и чтобы добраться до его имени, is удалите.

Так что посмотрим на это с этой стороны. Теперь давайте посмотрим на это с другой стороны, вы пишете класс, в котором по какой-либо причине вы решили, что полю должно быть присвоено имя isAvailable . Реальный вопрос заключается в следующем: как вы хотите, чтобы «свойство» было названо (в соответствии со спецификацией beanspec)? Если это действительно должно быть вызвано isAvailable , есть только один способ добиться этого:

 class Example {
    public boolean isIsAvailable() {
        return true;
    }
}
  

Да, isIsAvailable . Выглядит глупо, но это то, что предписывают правила, если вы хотите, чтобы вызывалось само свойство isAvailable . Ломбок решил (ИСТОЧНИК: я основной участник), что никому на самом деле не нужен метод с именем, isIsAvailable когда вы вставляете @Getter аннотацию в поле с именем isAvailable .

Итак, теперь у вас есть класс, который эффективно выглядит, насколько это касается Джексона:

 class Availability {
    @JsonProperty("isAvailable") private boolean isAvailable;

    public boolean isAvailable() { return this.isAvailable; }
}
  

Не используя никаких специальных интеллектуальных данных, просто применяя правила literal, означает, что Джексон говорит: Хорошо, здесь есть 2 разных свойства, available (получаемые путем вызова isAvailable() ) и isAvailable поле. Для геттеров в стиле beanspec is / get удаляется, для полей это не так, особенно если вы вставляете там @JsonProperty("isAvailable") .

Это контекст, объясняющий, почему все это происходит.

Решением могло бы быть создание этого метода:

 @JsonProperty("available")
public boolean getAvailable() { return this.available; }
  

Я думаю, что это даст вам оба варианта в вашем выводе JSON.

Комментарии:

1. Я ценю ваши комментарии. Работа с устаревшим кодом — это, конечно, неприятность, и я понимаю спецификацию Java bean и то, как Джексону и Ломбоку приходится иметь с этим дело. Я немного озадачен тем, почему поведение изменилось при изменении зависимостей, а базовый pojo не был изменен.

2. Я бы сказал, что обычно вывод ‘available’ и ‘isAvailable’ таким образом нежелателен, поэтому, предположительно, jackson обновлен до того же уровня интеллекта, что и lombok. Мы в lombok несколько раз нарушали обратную совместимость в таких экзотических случаях, не придавая этому особого значения (без версии 2.0 или чего-то еще), может быть, они тоже?

3. Я скажу вам, что написание getter со свойством json таким образом, безусловно, сработало, но пришло время договориться с клиентами и изменить контракт. Почему никто не заметил этого раньше, отстой. Я ненавижу наследование кода, но иногда такова жизнь в мире программного обеспечения! Еще раз спасибо, и Lombok, кстати, является шаблонным спасением.