On Mon, Mar 14, 2022 at 1:34 AM Michael Schäfer <[email protected]> wrote:
>
> Hi Again,
>
> can really nobody help me? Is important information missing from my request? 
> And off course this is a stripped version of my code to reproduce the case. I 
> really need the inheritance. To me this also looks like the final road block. 
> It would be really nice when I could get some feedback from a more 
> experienced dev.

I can only speculate that this is a limitation of the XML module, and
sounds like a bug.
I suggest you file an issue against `jackson-dataformat-xml`.

Unfortunately handling of `@JsonTypeInfo` in the XML module is tricky:
the problem may be due to buffering needed.

On issue it would be good to have a minimal (smallest possible)
reproduction of the problem. I realize that example is already
stripped down version but anything can help.

-+ Tatu +-

>
> Regards,
> Michael
>
> Michael Schäfer schrieb am Mittwoch, 2. März 2022 um 16:47:49 UTC+1:
>>
>> Hi guys,
>>
>> I'm currently facing an odd behavior with how polymorphic XML objects are 
>> deserialized when using Jackson 2.13.1. The deserialization fails when the 
>> type attribute is not the first attribute in the setting tag. This seems 
>> odd, as Jackson can even properly determine the correct type. My issue with 
>> this case is that my code has to handle XML documents that are generated by 
>> a source I don't have control over and it sadly generates XML documents 
>> where the type attribute is put last. So for example the following XML works:
>>
>> <setting type="localizedString" key="testKey">
>>         <value locale="default">testValue</value>
>>         <value locale="de-DE">testValue deutsch</value>
>> </setting>
>>
>> and the following XML fails:
>>
>> <setting key="testKey" type="localizedString">
>>         <value locale="default">testValue</value>
>>         <value locale="de-DE">testValue deutsch</value>
>> </setting>
>>
>> with the following error:
>> com.fasterxml.jackson.databind.JsonMappingException: Unexpected 
>> non-whitespace text ('testValue' in Array context: should not occur (or 
>> should be handled)
>>  at [Source: (StringReader); line: 2, column: 42] (through reference chain: 
>> ch.michael.experimental.JacksonInheritanceOrder$LocalizedSetting["value"])
>>         at 
>> com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:392)
>>         at 
>> com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:351)
>>         at 
>> com.fasterxml.jackson.databind.deser.BeanDeserializerBase.wrapAndThrow(BeanDeserializerBase.java:1821)
>>         at 
>> com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:315)
>>         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.impl.TypeWrappedDeserializer.deserialize(TypeWrappedDeserializer.java:74)
>>         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 
>> ch.michael.experimental.JacksonInheritanceOrder.executeTest(JacksonInheritanceOrder.java:143)
>>         at 
>> ch.michael.experimental.JacksonInheritanceOrder.deserializeTrailingType(JacksonInheritanceOrder.java:128)
>>         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.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
>>         at 
>> org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
>>         at 
>> org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
>>         at 
>> org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
>>         at 
>> org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
>>         at 
>> org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
>>         at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
>>         at 
>> org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
>>         at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
>>         at 
>> org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
>>         at 
>> org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
>>         at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
>>         at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
>>         at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
>>         at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
>>         at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
>>         at 
>> org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
>>         at 
>> org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
>>         at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
>>         at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
>>         at 
>> org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:93)
>>         at 
>> org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:40)
>>         at 
>> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:529)
>>         at 
>> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:756)
>>         at 
>> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:452)
>>         at 
>> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
>> Caused by: com.fasterxml.jackson.core.JsonParseException: Unexpected 
>> non-whitespace text ('testValue' in Array context: should not occur (or 
>> should be handled)
>>  at [Source: (StringReader); line: 2, column: 42]
>>         at 
>> com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:2391)
>>         at 
>> com.fasterxml.jackson.dataformat.xml.deser.FromXmlParser.nextToken(FromXmlParser.java:847)
>>         at 
>> com.fasterxml.jackson.core.util.JsonParserSequence.nextToken(JsonParserSequence.java:151)
>>         at 
>> com.fasterxml.jackson.databind.deser.std.CollectionDeserializer._deserializeFromArray(CollectionDeserializer.java:346)
>>         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.MethodProperty.deserializeAndSet(MethodProperty.java:129)
>>         at 
>> com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:313)
>>         ... 43 more
>>
>> For demo purposes I have create the following little demo test:
>>
>> import static org.junit.Assert.assertEquals;
>>
>> import java.util.LinkedList;
>> import java.util.List;
>>
>> import org.junit.After;
>> import org.junit.AfterClass;
>> import org.junit.Before;
>> import org.junit.BeforeClass;
>> import org.junit.Test;
>>
>> import com.fasterxml.jackson.annotation.JsonInclude;
>> import com.fasterxml.jackson.annotation.JsonSubTypes;
>> import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
>> import com.fasterxml.jackson.annotation.JsonTypeInfo;
>> 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.dataformat.xml.annotation.JacksonXmlText;
>>
>> public class JacksonInheritanceOrder {
>>
>>   @JsonInclude(JsonInclude.Include.NON_NULL)
>>   @JacksonXmlRootElement(localName = "setting")
>>   @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = 
>> JsonTypeInfo.As.EXISTING_PROPERTY, property = Setting.ATTRIBUTE_TYPE)
>>   @JsonSubTypes({@Type(value = LocalizedSetting.class, name = 
>> LocalizedSetting.TYPE)})
>>   public static interface Setting {
>>
>>     public static final String ATTRIBUTE_TYPE = "type";
>>
>>     @JacksonXmlProperty(localName = "key", isAttribute = true)
>>     public String getKey();
>>
>>     public void setKey(String key);
>>
>>     @JacksonXmlProperty(localName = ATTRIBUTE_TYPE, isAttribute = true)
>>     public String getType();
>>   }
>>
>>   public static class LocalizedSetting implements Setting {
>>
>>     public static final String TYPE = "localizedString";
>>
>>     @JacksonXmlProperty(localName = "key", isAttribute = true)
>>     private String key;
>>
>>     @JacksonXmlElementWrapper(useWrapping = false)
>>     @JacksonXmlProperty(localName = "value")
>>     private List<LocalizedValue> localizedValues = new LinkedList<>();
>>
>>     @Override
>>     public String getKey() {
>>       return key;
>>     }
>>
>>     @Override
>>     public void setKey(String key) {
>>       this.key = key;
>>     }
>>
>>     public List<LocalizedValue> getLocalizedValues() {
>>       return localizedValues;
>>     }
>>
>>     public void setLocalizedValues(List<LocalizedValue> values) {
>>       this.localizedValues = values;
>>     }
>>
>>     @Override
>>     public String getType() {
>>       return TYPE;
>>     }
>>   }
>>
>>   @JacksonXmlRootElement(localName = "value")
>>   public static class LocalizedValue {
>>
>>     @JacksonXmlProperty(localName = "locale", isAttribute = true)
>>     private String locale;
>>
>>     @JacksonXmlText
>>     private String value;
>>
>>     public String getLocale() {
>>       return locale;
>>     }
>>
>>     public void setLocale(String locale) {
>>       this.locale = locale;
>>     }
>>
>>     public String getValue() {
>>       return value;
>>     }
>>
>>     public void setValue(String value) {
>>       this.value = value;
>>     }
>>   }
>>
>>   @BeforeClass
>>   public static void setUpBeforeClass() throws Exception {}
>>
>>   @AfterClass
>>   public static void tearDownAfterClass() throws Exception {}
>>
>>   @Before
>>   public void setUp() throws Exception {}
>>
>>   @After
>>   public void tearDown() throws Exception {}
>>
>>   private static final String XML_TMPL = "<setting%s key=\"testKey\"%s>\n"
>>       + "<value locale=\"default\">testValue</value>\n"
>>       + "<value locale=\"de-DE\">testValue deutsch</value>\n"
>>       + "</setting>";
>>
>>   /**
>>    * Fails with JsonMappingException?!
>>    *
>>    * @throws Exception
>>    */
>>   @Test
>>   public void deserializeTrailingType() throws Exception {
>>     executeTest(String.format(XML_TMPL, "", " type=\"localizedString\""));
>>   }
>>
>>   /**
>>    * Works as expected.
>>    *
>>    * @throws Exception
>>    */
>>   @Test
>>   public void deserializeLeadingType() throws Exception {
>>     executeTest(String.format(XML_TMPL, " type=\"localizedString\"", ""));
>>   }
>>
>>   private void executeTest(String xmlInput) throws Exception {
>>     XmlMapper xmlMapper = new XmlMapper();
>>     Setting setting = xmlMapper.readValue(xmlInput, Setting.class);
>>     assertEquals("testKey", setting.getKey());
>>
>>     assertEquals(LocalizedSetting.class, setting.getClass());
>>     List<LocalizedValue> values = 
>> ((LocalizedSetting)setting).getLocalizedValues();
>>     assertEquals(2, values.size());
>>     assertEquals("default", values.get(0).getLocale());
>>     assertEquals("testValue", values.get(0).getValue());
>>     assertEquals("de-DE", values.get(1).getLocale());
>>     assertEquals("testValue deutsch", values.get(1).getValue());
>>   }
>> }
>>
>> Is this a bug or known issue? Can I work around it?
>
> --
> You received this message because you are subscribed to the Google Groups 
> "jackson-user" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to [email protected].
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/jackson-user/0afadee1-5b12-4b33-874c-d4f2632a511cn%40googlegroups.com.

-- 
You received this message because you are subscribed to the Google Groups 
"jackson-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/jackson-user/CAL4a10g-%3Dzt3NCMDtRnY%3D1rOAD0GV%3D0FQuhJH_jMQ2PADUpj_A%40mail.gmail.com.

Reply via email to