jackson-module-kotlin: InvalidDefinitionException in case of deserialization xml to data class with @JacksonXmlText annotation
Data class example:
@JacksonXmlRootElement(localName = "sms")
@JsonIgnoreProperties(ignoreUnknown = true)
data class Sms(
@set:JacksonXmlProperty(localName = "Phone", isAttribute = true)
var phone: String?,
@JacksonXmlText
var text: String? = ""
)
Corresponding xml:
<sms Phone="435242423412" Id="43234324">Lorem ipsum</sms>
Deserialization causes such output:
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Invalid definition for property `` (of type `proton72.github.com.Sms`): Could not find creator property with name '' (known Creator properties: [Phone, text])
at [Source: (StringReader); line: 1, column: 1]
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:62)
at com.fasterxml.jackson.databind.DeserializationContext.reportBadPropertyDefinition(DeserializationContext.java:1446)
at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.addBeanProps(BeanDeserializerFactory.java:567)
at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.buildBeanDeserializer(BeanDeserializerFactory.java:227)
at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:137)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer2(DeserializerCache.java:411)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:349)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:264)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244)
at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:477)
at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:4178)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3997)
Reproduced on jackson-dataformat-xml and jackson-module-kotlin 2.9.4 both.
About this issue
- Original URL
- State: open
- Created 6 years ago
- Reactions: 7
- Comments: 16 (8 by maintainers)
Commits related to this issue
- unclear why Github #138 fails, test case marked ignore showing the problem — committed to FasterXML/jackson-module-kotlin by apatrida 6 years ago
Outdated, I recommend to use
setXMLTextElementName
.Based on the above discovery here’s another workaround (instead of using JsonNode):
Note: this is not a solution as the field will be writable (
var
,private set
helps a bit, but still), will have no construct-time validation that the field is set (lateinit
), and the field will not play indata class
operations likeequals
,toString
, and others (it’s not in the primary constructor)!I just found someone on kotlin slack (named Stephan Schroeder) providing a solution :
You need a mapper like this :
and annotate your field like this:
This works for me with jackson 2.10.1. Slack user claims it works with jackson 2.9.9
Genius, it works for me too! Thank you very much for sharing @ctruchi! Note @ctruchi
@JacksonXmlText
doesn’t have an effect withsetXMLTextElementName
when deserializing only. However it is required for serialization.Following @ctruchi’s example this also works, with the benefit of not mixing XML and JSON annotations:
@cowtowncoder To move this a bit forward…
Here’s a base repro:
removing
@JacksonXmlText
works as expected, but obviously doesn’t deserialize the text:Commenting/removing the Kotlin Attribute class and using this instead works:
Getting a bit more close to Kotlin data classes fails the same way as Kotlin:
Note: removing
registerModule(KotlinModule())
makes no difference.If we solve the Java version to work (maybe the annotations are wrong), we could figure out how to do the same in Kotlin.
I was using the
innerText
workaround mentioned above but after updating to a newer version of the library, this no longer worked for me either.Using version 2.12.6 of
jackson-dataformat-xml
andjackson-module-kotlin
I had to move the property out of the constructor (and make it a nullable var), as a result had to stop using a data class as these require at least one constructor parameter. Using the@JacksonXmlText
meant I didn’t need theinnerText
anymore. This was for deserializing only as this was all I required.For this XML:
The following worked for me:
I was still able to use the builder method for creating the XmlMapper, without the need for
nameForTextElement("innerText")
.Haven’t tried this on 2.13.x and above versions yet.