Джексон-десериализатор - замените нулевую коллекцию на пустой

У меня есть объект, который содержит коллекцию как атрибут:

public class Entity {

    @JsonProperty(value="homes")
    @JsonDeserialize(as=HashSet.class, contentAs=HomeImpl.class)
    private Collection<Home> homes = new ArrayList<Home>();

}

Если запрос содержит null как свойство запроса:

{
  "homes": null
}

тогда для домов установлено значение null. То, что я хочу сделать, - это установить дома для пустого списка. Нужно ли мне писать специальный десериализатор для этого или есть ли для коллекций? То, что я пробовал, - это десериализатор, но он выглядит уродливым (он не является общим и использует реализацию вместо интерфейса).

public class NotNullCollectionDeserializer extends JsonDeserializer<Collection<HomeImpl>> {

  @Override
  public Collection<HomeImpl> deserialize(final JsonParser jsonParser, final DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
    return jsonParser.readValueAs(new TypeReference<Collection<HomeImpl>>(){});
  }

  @Override
  public Collection<HomeImpl> getNullValue() {
    return Collections.emptyList();
  }
}

Так мало вопросов:

  • Есть ли какое-то свойство jackson, которое изменяет значение null на пустую коллекцию во время десериализации?
  • Если нет для первой точки - мне нужно написать десериализатор для этого? Если да, могу ли я написать общий текст?

Ответ 1

Я также не мог найти свойство Джексона или аннотацию для этого. Поэтому я должен ответить на первый вопрос. Но я бы рекомендовал простой сеттер вместо специального десериализатора:

public class Entity {

    @JsonDeserialize(contentAs = HomeImpl.class)
    private Collection<Home> homes = new ArrayList<>();

    public void setHomes(List<Home> homes) {
        if (homes != null)
            this.homes = homes;
    }
}

Это общий, поскольку он использует только интерфейс Home вместо HomeImpl. Вам не нужно @JsonProperty, поскольку Джексон будет ассоциировать setHomes и homes.

Ответ 2

Начиная с Jackson 2.9, похоже, что обработка нулевых @JsonSetter для определенных свойств может быть настроена с помощью @JsonSetter, например:

@JsonSetter(nulls = Nulls.AS_EMPTY)
public void setStrings(List<String> strings) {
    this.strings = strings;
}

Аналогичная конфигурация также может применяться глобально для коллекций:

ObjectMapper mapper = objectMapperBuilder()
    .changeDefaultNullHandling(n -> n.withContentNulls(Nulls.AS_EMPTY))
    .build();

Или по типу:

ObjectMapper mapper = objectMapperBuilder()
    .withConfigOverride(List.class,
        o -> o.setNullHandling(JsonSetter.Value.forContentNulls(Nulls.AS_EMPTY)))
    .build();

Я не смог опробовать эту функцию, так что это основано на обсуждении функции и проверке модульных тестов. YMMV.

Ответ 3

Что сработало для меня было просто удалить сеттер и сделать атрибут окончательным. jackson 2 будет использовать геттер для изменения списка.

public class Entity {

  @JsonProperty(value="homes")
  @JsonDeserialize(as=HashSet.class, contentAs=HomeImpl.class)
  private final Collection<Home> homes = new ArrayList<Home>();

  public List<Home> getHomes() {
     return homes;
  }
}

Ответственной функцией является USE_GETTERS_AS_SETTERS, которая включена по умолчанию: https://github.com/FasterXML/jackson-databind/wiki/Mapper-Features