@JacksonXmlElementWrapper doesn’t work with data classes
See original GitHub issueI want to mapping a xml using kotlin data class, my xml wrapper a list of elements in a wapper node.
Xml example: <MyPojo><elements><element value="e1"/></elements></MyPojo>
Here the <element> node is a collection, wrapped in the <elements> node.
When I use the data class to map the ‘MyPojo’ and ‘element’ object and I annotated the collection property with @JacksonXmlElementWrapper
and @JacksonXmlProperty
it doesn’t work when I try to deserialise form xml.
The exception is:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Invalid definition for property elements
(of type MyDataPojo
): Could not find creator property with name ‘elements’ (known Creator properties: [element])
I use :
- Java 1.8
- Kotlin 1.2.31
- Jackson: 2.9.5
I have write a test to compare the mapping using the standard class and the data class. The standard class test passed, the data class test failed.
import com.fasterxml.jackson.dataformat.xml.XmlMapper
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement
import com.fasterxml.jackson.module.kotlin.KotlinModule
import junit.framework.Assert.assertEquals
import org.junit.Test
/**
* Mapping the Xml with standard classes
*/
@JacksonXmlRootElement(localName = "MyPojo")
class MyPojo {
@JacksonXmlElementWrapper(localName = "elements")
@JacksonXmlProperty(localName = "element")
var list: List<MyElement>? = null
}
/**
* Mapping the Xml with standard classes
*/
class MyElement {
@JacksonXmlProperty(localName = "value", isAttribute = true)
var value: String? = null
}
/**
* Mapping the Xml with data classes
*/
@JacksonXmlRootElement(localName = "MyPojo")
data class MyDataPojo (
@JacksonXmlElementWrapper(localName = "elements")
@JacksonXmlProperty(localName = "element")
val list
: List<MyDataElement>
)
/**
* Mapping the Xml with data classes
*/
data class MyDataElement (
@JacksonXmlProperty(localName = "value", isAttribute = true)
var value: String
)
class TextKotlinXmlWrapper {
// xml example I want to deserialize
val xml = """<MyPojo><elements><element value="e1"/></elements></MyPojo>"""
val mapper = XmlMapper()
.registerModule(KotlinModule())
@Test
@Throws(Exception::class)
fun test_class() {
// I create a pojo from the xml using the standard classes
val pojoFromXml = mapper.readValue(xml, MyPojo::class.java)
//I create a xml from the pojo
val xmlFromPojo = mapper.writeValueAsString(pojoFromXml)
// I compare the original xml with the xml generated from the pojo
assertEquals(xml, xmlFromPojo)
}
@Test
@Throws(Exception::class)
fun test_data_class() {
// I create a pojo from the xml using the data classes
val pojoFromXml = mapper.readValue(xml, MyDataPojo::class.java)
//I create a xml from the pojo
val xmlFromPojo = mapper.writeValueAsString(pojoFromXml)
// I compare the original xml with the xml generated from the pojo
assertEquals(xml, xmlFromPojo)
}
}
Issue Analytics
- State:
- Created 5 years ago
- Reactions:15
- Comments:25 (8 by maintainers)
Hi guys, Just in case it helps somebody else, I found a workaround by combining the things mentioned here with a property backed up with a constructor field.
This allow us to still use a data class and avoid writing getters/setters/hashcode/equals.
It is not too elegant, but it works fine so hopefully it will help.
Thanks guys for helping me figuring it out!
FYI, from Kotlin you can specify where the annotation lands, using the
get:
orfield:
prefixes between the@
and the annotation name. So the following should work: