杰克逊将单个项目反序列化为列表
Posted
技术标签:
【中文标题】杰克逊将单个项目反序列化为列表【英文标题】:Jackson deserialize single item into list 【发布时间】:2016-05-14 01:34:51 【问题描述】:我正在尝试使用一项服务,该服务为我提供了一个实体,该实体具有一个字段,它是一个数组。
"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...
有没有直接的解决方案?
【问题讨论】:
该服务的行为似乎很奇怪。有机会告诉提供商解决这个问题吗? @Thomas 不幸的是没有。这是一家拥有数百名用户的大型 SaaS 提供商,而我只是其中之一。 我已经为 JSON:API 添加了标签,因为这是可能发现这种令人讨厌的行为的上下文。 【参考方案1】:@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);
【讨论】:
【参考方案2】:我认为注释更适合代码。
@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
private List<Item> items;
【讨论】:
如果这不起作用并且您正在使用 lombok:您必须将此字段设为非final
并使用@NoArgsContructor
。它不适用于final
字段。
不幸的是,它似乎不适用于@JsonValue
。【参考方案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
您需要将此杰克逊功能添加到您的对象映射器中。
希望对你有帮助。
【讨论】:
【参考方案4】:可以使用自定义的 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;
你需要告诉杰克逊用它来反序列化items
,比如:
@JsonDeserialize(using = CustomDeserializer.class)
private List<Item> items;
之后它将起作用。快乐编码:)
【讨论】:
这很糟糕。不适用于您可能希望将单个值作为多个级别的数组的深层结构。使用单独的映射器以默认方式反序列化整个 List以上是关于杰克逊将单个项目反序列化为列表的主要内容,如果未能解决你的问题,请参考以下文章