On Jackson 2.9.8
If we use a DeserializerModifier that delegates to the original deserializer, the useWrapping = false on JacksonXmlElementWrapper no longer works. For a basic example (in Kotlin):
@JacksonXmlRootElement(localName = "batch")
class Batch(
@field:JacksonXmlElementWrapper(useWrapping = false)
@field:JacksonXmlProperty(localName = "message")
val messages: List<Message>
)
@JacksonXmlRootElement(localName = "message")
class Message(
@field:JacksonXmlProperty(localName = "text")
val text: String
)
private class CustomDeserializerModifier() : BeanDeserializerModifier() {
override fun modifyDeserializer(
config: DeserializationConfig,
beanDescription: BeanDescription,
jsonDeserializer: JsonDeserializer<*>
): JsonDeserializer<*> {
return CustomDeserializer(jsonDeserializer)
}
}
private class CustomDeserializer(deserializer: JsonDeserializer<*>) : DelegatingDeserializer(deserializer) {
override fun newDelegatingInstance(newDelegatee: JsonDeserializer<*>): JsonDeserializer<*> {
return newDelegatee
}
}
val xmlMapper = XmlMapper().registerKotlinModule().apply {
registerModule(SimpleModule().apply {
setDeserializerModifier(CallbackDeserializerModifier(params))
})
}
val deserialized = xmlMapper.readValue("<batch><message><text>one</text></message><message><text>two</text></message></batch>")
This gives me:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.example.example.models.GroupMessage$Receive` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('text')
at [Source: (StringReader); line: 1, column: 54] (through reference chain: com.example.example.models.Batch["batch"]->java.util.ArrayList[0])
at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1343)
at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1032)
at com.fasterxml.jackson.databind.deser.ValueInstantiator._createFromStringFallbacks(ValueInstantiator.java:371)
at com.fasterxml.jackson.databind.deser.std.StdValueInstantiator.createFromString(StdValueInstantiator.java:323)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromString(BeanDeserializerBase.java:1373)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:171)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:161)
at com.fasterxml.jackson.databind.deser.std.DelegatingDeserializer.deserialize(DelegatingDeserializer.java:95)
at com.example.example.app.CustomDeserializer.deserialize(CustomDeserializer.kt:91)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:286)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:245)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:27)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:530)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeWithErrorWrapping(BeanDeserializer.java:528)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:417)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1287)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:326)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159)
at com.fasterxml.jackson.databind.deser.std.DelegatingDeserializer.deserialize(DelegatingDeserializer.java:95)
at com.example.example.app.CustomDeserializer.deserialize(CustomDeserializer.kt:91)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4013)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3023)
This doesn't happen if we don't use the CustomDeserializerModifier which theoretically should just pass through the serialize call through delegation.
I think I've pinpointed why this happens. The unwrapping happens because a XmlBeanDeserializerModifer is added to the list of modifiers, which wraps the standard deserializer with a WrapperHandlingDeserializer. This modifier is called AFTER my CustomDeserializerModifier when the modifiers are applied. The XmlBeanDeserializerModifier requires a BeanDeserializerBase to work and my modifier returns a DelegatingDeserializer (not a BeanDeserializerBase) so the modification doesn't happen and the unwrapping never occurs. To fix this, I think the unwrapping must happen in a fundamentally different way, or at least happen first before the other modifiers.
I fixed this for myself by modifying with a different XmlBeanDeserializerModifier before my modification occurs, though this isn't the best solution for the long term.
On Jackson 2.9.8
If we use a DeserializerModifier that delegates to the original deserializer, the
useWrapping = falseonJacksonXmlElementWrapperno longer works. For a basic example (in Kotlin):This gives me:
This doesn't happen if we don't use the
CustomDeserializerModifierwhich theoretically should just pass through the serialize call through delegation.I think I've pinpointed why this happens. The unwrapping happens because a XmlBeanDeserializerModifer is added to the list of modifiers, which wraps the standard deserializer with a WrapperHandlingDeserializer. This modifier is called AFTER my CustomDeserializerModifier when the modifiers are applied. The XmlBeanDeserializerModifier requires a BeanDeserializerBase to work and my modifier returns a DelegatingDeserializer (not a BeanDeserializerBase) so the modification doesn't happen and the unwrapping never occurs. To fix this, I think the unwrapping must happen in a fundamentally different way, or at least happen first before the other modifiers.
I fixed this for myself by modifying with a different XmlBeanDeserializerModifier before my modification occurs, though this isn't the best solution for the long term.