XmlMapper fails to parse XML array when the array only has one level
Version used
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-xml -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.13.0</version>
</dependency>
Java versions tested
OpenJDK 1.8, 11 and 16
Test data
<?xml version="1.0" encoding="UTF-8"?>
<result>
<hello>world</hello>
<lists>1</lists>
<lists>2</lists>
<lists></lists>
<lists>
<inner>internal</inner>
<time>2021-10-27T21:18:46.217Z</time>
</lists>
<lists>3</lists>
<lists>test</lists>
<lists></lists>
<single>one</single>
</result>
Incorrect result by XmlMapper readValue(string, Map.class) method
{
"hello": "world",
"single": "one",
"lists": "test"
}
The array (as "lists" in the test data) contains 6 elements but XmlMapper returns only the last element.
Experiencing a similar issue with XML lists:
<?xml version="1.0" encoding="utf-8"?>
<ContentMeta>
<Type>Application</Type>
<Id>0x01006fe013472000</Id>
<Version>0</Version>
<Content>
<Type>Program</Type>
<Id>2b0153c1bb7ceb9cd84e7eb9e0e2288d</Id>
</Content>
<Content>
<Type>Control</Type>
<Id>32ec02fa4709c28a099d6670590e025b</Id>
</Content>
</ContentMeta>
data class ContentMeta(
val type: String,
val id: String,
val version: Int,
val content: Content // not a list -> gets last
)
mapper.readValue<ContentMeta>(xml)
// => ContentMeta(type="Application", id="0x01006fe013472000", version=0, content=Content(type="Control"))
data class ContentMeta(
val type: String,
val id: String,
val version: Int,
val content: List<Content> // list -> fails
)
mapper.readValue<ContentMeta>(xml)
// => Exception in thread "Indexing thread" com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `Content` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('Program')
@ericcwlaw Looks like a bug, yes.
@martmists-gh Not same issue just because there's List somewhere; please file separate one if you want -- will require pure-Java implementation, however, cannot have Kotlin dependency in this module. Or file against Kotlin module
@Martmists-GH quick note: not sure why, but use of nominal target of Object instead of Map seems to result in proper merging. So you may be able to work around the issue on short term.
I will add a failing test first, see if I can figure out what might be causing the problem. I'll also try to see if this might be different with root values (where generic types are a constant source of issues) vs. "Map as a property" (wrapper POJO with single Map valued property).
Ok another little note: use of Wrapper POJO like:
public class MapHolder {
public Map<String,Object> map;
}
also changes things so that binding works as expected.
So the problem affects only the specific case of Root value being bound as Map.
Note to self: use of "untyped" target (Object.class) is due to UntypedObjectDeserializer handling duplicate squashing but Map one not. Ugh.
Will file an issue against jackson-databind to try to fix.
Fixed via jackson-databind; will work in 2.14.0-rc2 (and 2.14.0 final)