杰克逊将单个项目反序列化为列表

Jackson deserialize single item into list

我正在尝试使用一项服务,该服务为我提供了一个实体,该实体的字段是一个数组。

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

但是当数组包含单个项目时,返回项目本身,而不是一个元素的数组。

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

在这种情况下,Jackson 无法转换为我的 Java 对象。

public class ResponseItem {

   private String id;
   private List<Item> items;

   //Getters and setters...
}

是否有直接的解决方案?

可以使用自定义 JsonDeserializer 来解决这个问题。

例如

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

}

你需要告诉 jackson 使用这个来反序列化 items,比如:

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

之后就可以了。编码愉快:)

您不是第一个提出这个问题的人。好像很老

看完这个问题,可以用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

您需要将此 jackson 功能添加到您的对象映射器中。

希望对你有所帮助

我认为注释更适合代码。

@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
private List<Item> items;

@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY) 似乎不适用于 @JsonValue

这意味着如果您想将其中任何一个反序列化为列表,它将无法工作:

{
  "key": true
}
[
  {
    "key": true
  },
  {
    "key": false
  }
]

作为一种解决方案,可以像这样创建自定义反序列化器:

@JsonDeserialize(using = CustomDeserializer.class)
public record ListHolder(List<Item> items) {}

public class CustomDeserializer extends JsonDeserializer<ListHolder> {

    @Override
    public ListHolder deserialize(JsonParser parser, DeserializationContext context) throws IOException {
        List<Item> items;

        if (parser.isExpectedStartArrayToken()) {
            items = parser.readValueAs(new TypeReference<>() {});
        } else {
            items = List.of(parser.readValueAs(Item.class));
        }

        return new ListHolder(items);
    }
}