Skip to content

XML de-/serialization of collection/array attributes not respecting UseWrapper when using maps  #431

@ghost

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    will-not-fixIssue for which there is no plan to fix as described or requested

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions