Home > Mobile >  Kotlin - Deserializing with Jackson XmlMapper
Kotlin - Deserializing with Jackson XmlMapper

Time:03-14

I'm having some trouble to parse correctly an XML file with Jackson XML Mapper. Suppose I have this simple XML:

<Test>
    <Simple>
        <x>I am x</x>
        <y>I am y</y>
    </Simple>
</Test>

and this simple class:

@Root(name="Simple",strict = false)
class Simple {

    @Element(name = "x", required = false)
    lateinit var x :String

    @Element(name = "y", required = false)
    lateinit var y :String
    
}

The compiler keeps throwing this error:

Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "Simple" (class Simple), not marked as ignorable (2 known properties: "x", "y"])

I guess it's because Kotlin can't find the proper structure of the file within the class? Problem is I need to parse a much more big xml file, and need to avoid to mirror every single Element of the xml, otherwise it will become huge.

So how can I "partially" parse the xml, setting the root to the <Simple> tag, avoiding the <Test> tag?

Thank you so much!

CodePudding user response:

Here's a working solution. Note that I've made the mapper case insensitive to cope with the capitalised Simple property in the XML. You could do this with an annotation on the property instead to override the default lower case name. Note also the use of data classes that do away with any need to use lateinit vars or suchlike:

import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.MapperFeature
import com.fasterxml.jackson.dataformat.xml.JacksonXmlModule
import com.fasterxml.jackson.dataformat.xml.XmlMapper
import com.fasterxml.jackson.module.kotlin.registerKotlinModule


data class Simple(val x: String, val y: String)
data class Test(val simple: Simple)


fun main() {

    val xmlDeserializer = XmlMapper(JacksonXmlModule().apply {
        setDefaultUseWrapper(false)
    }).registerKotlinModule()
        .configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true)
        .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)

    val simple = Simple("x","y")
    val test = Test(simple)
    println(xmlDeserializer.writeValueAsString(test))

    val stringToParse = "<Test><Simple><x>1</x><y>2</y></Simple></Test>"
    val finalObject = xmlDeserializer.readValue(stringToParse, Test::class.java)
    println(finalObject.simple.x)
}

make sure your build.gradle.kts has these dependencies if they aren't there already:

implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.13.1")
implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.13.1")
  • Related