杰克逊将单个项目反序列化为列表
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
:
您需要将此 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);
}
}
我正在尝试使用一项服务,该服务为我提供了一个实体,该实体的字段是一个数组。
{
"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
:
您需要将此 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);
}
}