Hello,
I am trying to deserialize a rather complex Object, but I always got a "com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.util.ArrayList out of START_OBJECT token"
I have an abstract class, with two implementations.
This abstract class has a "value" field, which can be either a "simple" object (such as a String, an int, etc) or a collection (a List of items).
I'm able to deserialize my XML when I have a simple object, but it is failing with a collection.
If my collection is not in an abstract class, there is no issue. But it seems to be not possible to have an abstract class with a field being either a collection or not.
What I am missing ?
Thanks
Here is a unit test reproducing the problem:
public class DeserializationXmlTest {
@Test
public void deserializeXml_simple() throws IOException {
ObjectMapper objectMapper = new XmlMapper();
Pojo readValue = objectMapper.readValue("<root>" +
"<name>MyName</name>" +
"<field>" +
" <value>MyValue</value>" +
" <type>SIMPLE</type>" +
"</field>" +
"</root>", Pojo.class);
assertThat(readValue.name).isEqualTo("MyName");
assertThat(readValue.field).isInstanceOf(SimpleValue.class);
assertThat(readValue.field.type).isEqualTo("SIMPLE");
assertThat(readValue.field.value).isEqualTo("MyValue");
}
@Test
public void deserializeXml_list() throws IOException {
ObjectMapper objectMapper = new XmlMapper();
Pojo readValue = objectMapper.readValue("<root>" +
"<name>MyName</name>" +
"<field>" +
" <value>" +
" <item>Value1</item>" +
" <item>Value2</item>" +
" </value>" +
" <type>LIST</type>" +
"</field>" +
"</root>", Pojo.class);
assertThat(readValue.name).isEqualTo("MyName");
assertThat(readValue.field).isInstanceOf(ListValue.class);
assertThat(readValue.field.type).isEqualTo("LIST");
assertThat(readValue.field.value).isEqualTo(Arrays.asList("Value1", "Value2"));
}
@Test
public void deserializeXml_list_no_abstract() throws IOException {
ObjectMapper objectMapper = new XmlMapper();
Pojo readValue = objectMapper.readValue("<root>" +
"<name>MyName</name>" +
"<listValue>" +
" <value>" +
" <item>Value1</item>" +
" <item>Value2</item>" +
" </value>" +
"</listValue>" +
"</root>", Pojo.class);
assertThat(readValue.name).isEqualTo("MyName");
assertThat(readValue.listValue).isInstanceOf(NoAbstractListValue.class);
assertThat(readValue.listValue.value).isEqualTo(Arrays.asList("Value1", "Value2"));
}
@JacksonXmlRootElement(localName = "root")
@JsonIgnoreProperties(ignoreUnknown = true)
public static class Pojo {
@JsonProperty
private String name;
@JsonProperty
private AbstractValue field;
@JsonProperty(required = false)
private NoAbstractListValue listValue;
}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = SimpleValue.class, name = "SIMPLE"),
@JsonSubTypes.Type(value = ListValue.class, name = "LIST")
})
public static class AbstractValue<T> {
protected String type;
protected T value;
public AbstractValue(String type) {
this.type = type;
}
}
public static class SimpleValue extends AbstractValue<String> {
public SimpleValue() {
super("SIMPLE");
}
@JsonProperty
public void setValue(String value) {
this.value = value;
}
}
public static class ListValue extends AbstractValue<List<String>> {
public ListValue() {
super("LIST");
}
@JsonProperty
@JacksonXmlElementWrapper(localName = "value")
@JacksonXmlProperty(localName = "item")
public void setValue(List<String> value) {
this.value = value;
}
}
public static class NoAbstractListValue {
protected List<String> value;
public NoAbstractListValue() {
}
@JsonProperty
@JacksonXmlElementWrapper(localName = "value")
@JacksonXmlProperty(localName = "item")
public void setValue(List<String> value) {
this.value = value;
}
}
}
When running this test, the deserializeXml_simple and deserializeXml_list_no_abstract will succeed, but not deserializeXml_list.