-
-
Notifications
You must be signed in to change notification settings - Fork 233

Description
(tested with 2.11.3 and 2.12.0-rc1)
I'm reading dynamic json and xml data using Jackson, so I mostly work with Map<String,Object> instead of POJOs. When converting these maps to/from XML I found some unusual behaviour which I think is a bug. It occurs when the values contained in the map are Collections or Arrays.
To replicate I use a simple POJO which I would suspect to behave very similar to using a Map with a list entry named "myList":
static class SomePojo {
public List<String> myList = new ArrayList<>();
@Override
public String toString() {
return "SomePojo[myList=" + String.valueOf(myList) + "]";
}
}
Therefore I would expect the xml to look like:
static final String XML_WITH_WRAPPER = "<daRoot><myList><myList>string1</myList><myList>string2</myList></myList></daRoot>";
static final String XML_NO_WRAPPER = "<daRoot><myList>string1</myList><myList>string2</myList></daRoot>";
In the unit tests below I further use a simple helper method:
private static XmlMapper createXmlMapper(boolean useWrapper) {
XmlMapper om = new XmlMapper();
om.setDefaultUseWrapper(useWrapper);
om.enable(SerializationFeature.INDENT_OUTPUT);
return om;
}
Testing serialization, the following test fails because the map-version doesn't seem to respect useWrapper:
@Test
public void xmlSerializationOfCollectionEntriesInMapsShouldRespectUseWrapper() throws IOException {
SomePojo pojo = new SomePojo();
pojo.myList = List.of("string1", "string2");
Map<String, Object> map = new HashMap<>();
map.put("myList", List.of("string1", "string2"));
ObjectWriter writer = createXmlMapper(true).writer().withRootName("daRoot");
String xmlFromModel = writer.writeValueAsString(pojo);
String xmlFromMap = writer.writeValueAsString(map);
System.out.println("xmlFromModel: " + xmlFromModel);
System.out.println("xmlFromMap: " + xmlFromMap);
assertThat("xml should match", xmlFromMap, equalTo(xmlFromModel));
}
Reading such xml to a POJO works as expected:
@Test
public void xmDeserializationToPojoShouldReadCompleteList() throws IOException {
SomePojo pojo = createXmlMapper(true).readValue(XML_WITH_WRAPPER, SomePojo.class);
System.out.println(pojo);
assertThat("all strings read with wrapper", pojo.myList, equalTo(List.of("string1", "string2")));
pojo = createXmlMapper(false).readValue(XML_NO_WRAPPER, SomePojo.class);
System.out.println(pojo);
assertThat("all strings read no wrapper", pojo.myList, equalTo(List.of("string1", "string2")));
}
But reading it to a Map<String,Object> fails. Reading XML_WITH_WRAPPER produces "{myList={myList=[string1, string2]}}", reading XML_NO_WRAPPER leads to "{myList=string2}", omitting "string1" altogether. In both cases I would expect the result to be "myList=[string1, string2]" to be consistent with POJOs:
@Test
public void xmlDeserializationToMapShouldReadCompleteList() throws IOException {
XmlMapper om1 = createXmlMapper(true);
JavaType type1 = om1.getTypeFactory().constructMapType(LinkedHashMap.class, String.class, Object.class);
Map<String, Object> map = om1.readValue(XML_WITH_WRAPPER, type1);
System.out.println(map);
assertThat("all strings read with wrapper", map.get("myList"), equalTo(List.of("string1", "string2")));
XmlMapper om2 = createXmlMapper(false);
JavaType type2 = om1.getTypeFactory().constructMapType(LinkedHashMap.class, String.class, Object.class);
map = om2.readValue(XML_NO_WRAPPER, type2);
System.out.println(map);
assertThat("all strings read no wrapper", map.get("myList"), equalTo(List.of("string1", "string2")));
}
It would be great if you could have a look at this.