Джексон десериализует один элемент в список

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

{
  "id": "23233",
  "items": [
    {
      "name": "item 1"
    },
    {
      "name": "item 2"
    }
  ]
}

Но когда массив содержит один элемент, возвращается сам элемент, а не массив из одного элемента.

{
  "id": "43567",
  "items": {
      "name": "item only"
    }
}

В этом случае Джексону не удается преобразовать мой объект Java.

public class ResponseItem {

   private String id;
   private List<Item> items;

   //Getters and setters...
}

Есть ли для него простое решение?


person Javier Alvarez    schedule 04.02.2016    source источник
comment
Это кажется довольно странным поведением для этой службы. Есть ли шанс сказать провайдеру, чтобы он это исправил?   -  person Thomas    schedule 04.02.2016
comment
@ Томас К сожалению, нет. Это крупный провайдер SaaS с сотнями пользователей, и я лишь один из них.   -  person Javier Alvarez    schedule 04.02.2016
comment
Я добавил тег для JSON:API, так как это контекст, в котором может быть обнаружено это неприятное поведение.   -  person chrylis -cautiouslyoptimistic-    schedule 12.07.2021


Ответы (3)


Вы не первый, кто задает эту проблему. Кажется довольно старым.

Посмотрев на эту проблему, вы можете использовать DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY :

Посмотрите документацию: http://fasterxml.github.io/jackson-databind/javadoc/2.5/com/fasterxml/jackson/databind/DeserializationFeature.html#ACCEPT_SINGLE_VALUE_AS_ARRAY

Вам нужно добавить эту функцию Джексона в ваш объектный картограф.

Я надеюсь, что это поможет вам.

person Thomas Betous    schedule 04.02.2016

Я думаю, что аннотация лучше подходит коду.

@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
private List<Item> items;
person Higarian    schedule 22.05.2020
comment
В случае, если это не работает, и вы используете ломбок: вы должны сделать это поле отличным от final и использовать @NoArgsContructor. Это не работает для final полей. - person lilalinux; 04.06.2021

Для решения этой проблемы можно использовать пользовательский JsonDeserializer.

E.g.

class CustomDeserializer extends JsonDeserializer<List<Item>> {

    @Override
    public List<Item> deserialize(JsonParser jsonParser, DeserializationContext context)
            throws IOException, JsonProcessingException {

        JsonNode node = jsonParser.readValueAsTree();

        List<Item> items = new ArrayList<>();
        ObjectMapper mapper = new ObjectMapper();

        if (node.size() == 1) {
            Item item = mapper.readValue(node.toString(), Item.class);
            items.add(item);

        } else {
            for (int i = 0; i < node.size(); i++) {
                Item item = mapper.readValue(node.get(i).toString(), Item.class);
                items.add(item);
            }
        }

        return items;
    }

}

вам нужно сказать Джексону использовать это для десериализации items, например:

@JsonDeserialize(using = CustomDeserializer.class)
private List<Item> items;

После этого он будет работать. Удачного кодирования :)

person Sachin Gupta    schedule 04.02.2016
comment
это плохо. не будет работать с глубокими структурами, где вам могут понадобиться отдельные значения в виде массивов на нескольких уровнях. Использование отдельного преобразователя для десериализации всей ветки List‹Item› способом по умолчанию. Дополнительный преобразователь создается при каждой десериализации списка. - person Radu Simionescu; 26.06.2017