Search code examples
xmlkotlinjackson

MismatchedInputException while deserializing XML lists with Jackson


I'm having an issue deserializing some XMl containing a list of objects.

To reproduce it, I first serialize a given object to XML, then try to deserialize the result, but it fails.

Here is my sample code:

fun main() {
    val test = CategoriesResponse(listOf(Category(1), Category(2)))
    val xmlMapper = XmlMapper()
    val xml: String = xmlMapper.writeValueAsString(test)
    println(xml)
    val testObject = xmlMapper.readValue(xml, CategoriesResponse::class.java)
    println(testObject)

}


@JacksonXmlRootElement(localName = "response")
data class CategoriesResponse
@JsonCreator
constructor(
    @field:JacksonXmlElementWrapper(localName = "categories")
    @field:JacksonXmlProperty(localName = "category")
    val categoryList: List<Category>
)

data class Category
@JsonCreator
constructor(
    @field:JacksonXmlProperty(isAttribute = true)
    val id: Int,
)

The produced XML is just right (formatted here):

<response>
   <categories>
      <category id="1"/>
      <category id="2"/>
   </categories>
</response> 

I'm using implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml")

And here is the exception I get:

Exception in thread "main" com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `java.util.ArrayList<Category>` from Object value (token `JsonToken.FIELD_NAME`)
 at [Source: (StringReader); line: 1, column: 11]
    at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)

Any help would be greatly appreciated. Thank you!


Solution

  • Something wrong with the constructor. I don't think @JsonCreator is suitable for XML. Consider adding default values so the parser will instantiate the objects by triggering their empty constructors.

    @JacksonXmlRootElement(localName = "response")
    data class CategoriesResponse(
        @field:JacksonXmlElementWrapper(localName = "categories")
        @field:JacksonXmlProperty(localName = "category")
        val categoryList: List<Category> = listOf()
    )
    
    data class Category(
        @field:JacksonXmlProperty(isAttribute = true)
        val id: Int = -1
    )