Jackson deserialize single item into list
You are not the first to ask for this problem. It seems pretty old.
After looking at this problem, you can use the DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY
:
Look at the documentation : http://fasterxml.github.io/jackson-databind/javadoc/2.5/com/fasterxml/jackson/databind/DeserializationFeature.html#ACCEPT_SINGLE_VALUE_AS_ARRAY
You need to add this jackson feature to your object mapper.
I hope it will help you.
A custom JsonDeserializer can be used to solve this.
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;
}
}
you need to tell jackson to use this to de-serialize items
, like:
@JsonDeserialize(using = CustomDeserializer.class)
private List<Item> items;
After that it will work. Happy coding :)
I think the anotation suits the code better.
@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
private List<Item> items;
@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
does not seem work with @JsonValue
.
Meaning it won't work if you want to deserialize either of these as a list:
{
"key": true
}
[
{
"key": true
},
{
"key": false
}
]
As a solution it's possible to create a custom deserializer like this:
@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);
}
}