I am trying to deserialise the following xml into the objects:
<?xml version="1.0" encoding="iso-8859-1" ?>
<foo>
<dean>
<bar>28</bar>
<bar>31</bar>
</dean>
</foo>
My classes are the following
public class Foo {
private final Dean dean;
public Foo(@JacksonXmlProperty(localName = "dean") final Dean dean) {
this.dean = dean;
}
public Dean getDean() {
return dean;
}
}
public class Dean {
@JacksonXmlElementWrapper(useWrapping = false)
private final List<Bar> bar;
public Dean(@JacksonXmlProperty(localName = "bar") final List<Bar> bar) {
this.bar = bar;
}
public List<Bar> getBar() {
return bar;
}
}
public class Bar {
@JacksonXmlText
private Integer value;
public Bar(@JacksonXmlProperty(localName = " ") Integer value) {
this.value = value;
}
public Integer getValue() {
return value;
}
}
My mapper dependencies are the following:
gradle
ext {
jacksonVersion = "2.8.9"
}
compile(group: "com.fasterxml.jackson.dataformat", name: "jackson-dataformat-
xml", version: "$jacksonVersion")
compile(group: "com.fasterxml.jackson.datatype", name: "jackson-datatype-
jsr310", version: "$jacksonVersion")enter code here
Here is the failing test with exception being thrown by the xmlMapper
@Test
public void shouldParseAndCreateObject() throws Exception {
final JacksonXmlModule jacksonXmlModule = new JacksonXmlModule();
XmlMapper xmlMapper = (XmlMapper) new XmlMapper(jacksonXmlModule)
.disable(FAIL_ON_UNKNOWN_PROPERTIES, FAIL_ON_IGNORED_PROPERTIES);
Foo foo = xmlMapper.readValue("<?xml version=\"1.0\" encoding=\"iso-8859-
1\" ?>\n" +
"<foo>\n" +
" <dean>\n" +
" <bar>28</bar>\n" +
" <bar>31</bar>\n" +
" </dean>\n" +
"</foo>", Foo.class);
assertThat(foo.getDean().getBar().get(0).getValue(), is(28));
}
com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of Bar: no String-argument constructor/factory method to deserialize from String value ('28')
at [Source: out/test/resources/test.xml; line: 4, column: 16] (through reference chain: service.Foo["dean"]->service.Dean["bar"]->java.util.ArrayList[0])
From reading the exception it looks like the mapper is treating the value 28 as a string rather than a Integer but if i change the Bar class to the following and add an attribute to element bar to the raw xml the same test passes.
public class Bar {
private String test;
@JacksonXmlText
private Integer value;
public Bar(@JacksonXmlProperty(localName = "test", isAttribute = true) String
test, @JacksonXmlProperty(localName = " ") Integer value) {
this.test = test;
this.value = value;
}
public String getTest() {
return test;
}
public Integer getValue() {
return value;
}
<?xml version="1.0" encoding="iso-8859-1" ?>
<foo>
<dean>
<bar test="haha1">28</bar>
<bar test="haha2">31</bar>
</dean>
</foo>
@Test
public void shouldParseAndCreateObject() throws Exception {
final JacksonXmlModule jacksonXmlModule = new JacksonXmlModule();
XmlMapper xmlMapper = (XmlMapper) new XmlMapper(jacksonXmlModule)
.disable(FAIL_ON_UNKNOWN_PROPERTIES, FAIL_ON_IGNORED_PROPERTIES);
Foo foo = xmlMapper.readValue("<?xml version=\"1.0\" encoding=\"iso-8859-
1\" ?>\n" +
"<foo>\n" +
" <dean>\n" +
" <bar test=\"haha1\">28</bar>\n" +
" <bar test=\"haha2\">31</bar>\n" +
" </dean>\n" +
"</foo>" +
"</foo>", Foo.class);
assertThat(foo.getDean().getBar().get(0).getValue(), is(28));
}
I would say that the Mapper should infer the type from the constructor parameter type and try to instantiate that object with the string value and under the hood do something like Integer.valueOf("28")
Add to POJO empty constructor and also for all fields. Also try the following:
JacksonXmlModule module = new JacksonXmlModule();
module.setDefaultUseWrapper(false);
XmlMapper xmlMapper = new XmlMapper(module);