Order of XML Properties trigger different behaviors with polymorphic nested objects
See original GitHub issueThis very specific structure fails to parse a correct XML when the xsi:type
property is placed after other fields in the XML. That’s the only difference between the test cases.
See below:
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule;
import org.testng.annotations.Test;
import javax.xml.bind.annotation.*;
import java.io.IOException;
import java.util.List;
import static org.junit.Assert.assertEquals;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "ModelInfo")
class ModelInfo {
protected List<TypeInfo> typeInfo;
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "TypeInfo")
@XmlSeeAlso({ ClassInfo.class })
abstract class TypeInfo {
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "ClassInfo")
class ClassInfo extends TypeInfo {
protected List<ClassInfoElement> element;
@XmlAttribute(required = true)
protected String name;
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "ClassInfoElement")
class ClassInfoElement {
protected BindingInfo binding;
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "BindingInfo")
class BindingInfo {
protected String description;
}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = ClassInfo.class)
})
interface TypeInfoMixIn {}
public class JacksonXMLTests {
XmlMapper mapper = new XmlMapper().builder()
.defaultUseWrapper(false)
.addMixIn(TypeInfo.class, TypeInfoMixIn.class)
.addModule(new JaxbAnnotationModule())
.build();
@Test
public void testTypeAfterOtherProperties() throws IOException {
String xml =
"<modelInfo xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" +
" <typeInfo name=\"MyName\" xsi:type=\"ClassInfo\">\n" +
" <element>\n" +
" <binding description=\"Test\"/>\n" +
" </element>\n" +
" </typeInfo>\n" +
"</modelInfo>";
ModelInfo m = mapper.readValue(xml, ModelInfo.class);
assertEquals("MyName", ((ClassInfo)m.typeInfo.get(0)).name);
assertEquals("Test", ((ClassInfo)m.typeInfo.get(0)).element.get(0).binding.description);
}
@Test
public void testTypeBeforeOtherProperties() throws IOException {
String xml =
"<modelInfo xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" +
" <typeInfo xsi:type=\"ClassInfo\" name=\"MyName\">\n" +
" <element>\n" +
" <binding description=\"Test\"/>\n" +
" </element>\n" +
" </typeInfo>\n" +
"</modelInfo>";
ModelInfo m = mapper.readValue(xml, ModelInfo.class);
assertEquals("MyName", ((ClassInfo)m.typeInfo.get(0)).name);
assertEquals("Test", ((ClassInfo)m.typeInfo.get(0)).element.get(0).binding.description);
}
}
Running this with:
compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.13.2'
compile group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-xml', version: '2.13.2'
compile group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: '2.13.2'
compile group: 'com.fasterxml.jackson.module', name: 'jackson-module-jaxb-annotations', version: '2.13.2'
Yields a pass on testTypeBeforeOtherProperties
and a fail on testTypeAfterOtherProperties
with the following stack:
Unrecognized field "description" (class org.cqframework.cql.cql2elm.ClassInfoElement), not marked as ignorable (one known property: "binding"])
at [Source: (StringReader); line: 4, column: 36] (through reference chain: org.cqframework.cql.cql2elm.ModelInfo["typeInfo"]->java.util.ArrayList[0]->org.cqframework.cql.cql2elm.ClassInfo["element"]->java.util.ArrayList[0]->org.cqframework.cql.cql2elm.ClassInfoElement["description"])
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "description" (class org.cqframework.cql.cql2elm.ClassInfoElement), not marked as ignorable (one known property: "binding"])
at [Source: (StringReader); line: 4, column: 36] (through reference chain: org.cqframework.cql.cql2elm.ModelInfo["typeInfo"]->java.util.ArrayList[0]->org.cqframework.cql.cql2elm.ClassInfo["element"]->java.util.ArrayList[0]->org.cqframework.cql.cql2elm.ClassInfoElement["description"])
at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:61)
at com.fasterxml.jackson.databind.DeserializationContext.handleUnknownProperty(DeserializationContext.java:1127)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:1989)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1700)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1678)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:319)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:176)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer._deserializeFromArray(CollectionDeserializer.java:355)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:244)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:28)
at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:138)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:313)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:214)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:186)
at com.fasterxml.jackson.dataformat.xml.deser.WrapperHandlingDeserializer.deserialize(WrapperHandlingDeserializer.java:122)
at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer._deserializeTypedForId(AsPropertyTypeDeserializer.java:144)
at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer.deserializeTypedFromObject(AsPropertyTypeDeserializer.java:110)
at com.fasterxml.jackson.databind.deser.AbstractDeserializer.deserializeWithType(AbstractDeserializer.java:263)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer._deserializeFromArray(CollectionDeserializer.java:357)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:244)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:28)
at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:138)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:313)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:176)
at com.fasterxml.jackson.dataformat.xml.deser.WrapperHandlingDeserializer.deserialize(WrapperHandlingDeserializer.java:122)
at com.fasterxml.jackson.dataformat.xml.deser.XmlDeserializationContext.readRootValue(XmlDeserializationContext.java:91)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4674)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3629)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3597)
at org.cqframework.cql.cql2elm.JacksonXMLTests.testTypeAfterOtherProperties(JacksonXMLTests.java:72)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:84)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:714)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:901)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1231)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111)
at org.testng.TestRunner.privateRun(TestRunner.java:767)
at org.testng.TestRunner.run(TestRunner.java:617)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:348)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:343)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:305)
at org.testng.SuiteRunner.run(SuiteRunner.java:254)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1224)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1149)
at org.testng.TestNG.run(TestNG.java:1057)
at org.gradle.api.internal.tasks.testing.testng.TestNGTestClassProcessor.runTests(TestNGTestClassProcessor.java:141)
at org.gradle.api.internal.tasks.testing.testng.TestNGTestClassProcessor.stop(TestNGTestClassProcessor.java:90)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
at com.sun.proxy.$Proxy5.stop(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.stop(TestWorker.java:132)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:412)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
at java.base/java.lang.Thread.run(Thread.java:834)
I am not sure if this is a JAXB Module issue or a DataFormat issue. I hope this is the right place.
Issue Analytics
- State:
- Created a year ago
- Reactions:3
- Comments:12 (5 by maintainers)
Top Results From Across the Web
Jackson polymorphic deserialization with type property that is ...
1 Answer 1 ... If you look at the Jackson Api AsPropertyTypeDeserializer is the class responsible for sub type identification using property. If ......
Read more >7 Defining Polymorphic View Objects - Oracle Help Center
The XML property DiscrColumn identifies the overridden CountryTypeCode attribute as the polymorphic discriminator attribute, with a subtype value of DOMESTIC .
Read more >Chapter 5. Basic O/R Mapping
Object /relational mappings are usually defined in an XML document. The mapping document is designed to be readable and hand-editable.
Read more >XSL Transformations (XSLT) Version 3.0 - W3C
3.1 XSLT Namespace; 3.2 Extension Attributes; 3.3 XSLT Media Type ... consisting of XSL formatting objects (see [XSL-FO]), or into another ...
Read more >Polymorphic serialization for object types - .NET
Using default configuration, System.Text.Json serializes values of type object using polymorphism. This behavior becomes less consistent if you ...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
Ok, I was able to reproduce the failure and added the failing test case as reproduction.
From exception it does look like there is a structural mismatch, which I suspect is due to buffering that is needed when the type id is NOT the first property being found (that is, buffering of non-type-id properties until type id is encountered and handled). That should not matter, of course.
Simplifying further to: