FasterXML / jackson-dataformat-xml

Extension for Jackson JSON processor that adds support for serializing POJOs as XML (and deserializing from XML) as an alternative to JSON
Apache License 2.0
562 stars 221 forks source link

Support case where element and attribute have same name #555

Open kalyansagi opened 1 year ago

kalyansagi commented 1 year ago

We are using jackson-dataformat-xml to convert an XML to JavaObject. Our use case is very peculiar such that the name of the attribute and element are the same in our XML. See the below sample.

`

`

JavaObject:

`@XmlRootElement public class Work {

@JacksonXmlProperty(localName = "Status", isAttribute = true)
String status;

@JacksonXmlProperty(localName = "Status", isAttribute = false)
Status status_1;

@JacksonXmlRootElement
static class Status {

    @JacksonXmlProperty(localName = "Status", isAttribute = true)
    String status;
}

}`

Implementation:

XmlMapper xmlMapper = new XmlMapper();
        try {
            Work workOrder = xmlMapper.readValue(sample, Work.class);
            System.out.println(workOrder.toString());
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }

Errors:

Exception in thread "main" java.lang.RuntimeException: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Multiple fields representing property "Status": com.example.demo.Work#status vs com.example.demo.Work#status_1
 at [Source: (StringReader); line: 1, column: 1]
    at com.example.demo.DemoApplication.main(DemoApplication.java:23)
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Multiple fields representing property "Status": com.example.demo.Work#status vs com.example.demo.Work#status_1
 at [Source: (StringReader); line: 1, column: 1]
    at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:62)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.buildBeanDeserializer(BeanDeserializerFactory.java:268)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:150)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer2(DeserializerCache.java:415)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:350)
    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:642)
    at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:4805)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4675)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3629)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3597)
    at com.example.demo.DemoApplication.main(DemoApplication.java:20)
Caused by: java.lang.IllegalArgumentException: Multiple fields representing property "Status": com.example.demo.Work#status vs com.example.demo.Work#status_1
    at com.fasterxml.jackson.databind.introspect.POJOPropertyBuilder.getField(POJOPropertyBuilder.java:627)
    at com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition.getAccessor(BeanPropertyDefinition.java:190)
    at com.fasterxml.jackson.databind.introspect.POJOPropertyBuilder._getSetterInfo(POJOPropertyBuilder.java:265)
    at com.fasterxml.jackson.databind.introspect.POJOPropertyBuilder.getMetadata(POJOPropertyBuilder.java:242)
    at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._anyIndexed(POJOPropertiesCollector.java:1238)
    at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._sortProperties(POJOPropertiesCollector.java:1140)
    at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.collectAll(POJOPropertiesCollector.java:470)
    at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.getPropertyMap(POJOPropertiesCollector.java:386)
    at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.getProperties(POJOPropertiesCollector.java:233)
    at com.fasterxml.jackson.databind.introspect.BasicBeanDescription._properties(BasicBeanDescription.java:164)
    at com.fasterxml.jackson.databind.introspect.BasicBeanDescription.findProperties(BasicBeanDescription.java:239)
    at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory._findCreatorsFromProperties(BasicDeserializerFactory.java:328)
    at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory._constructDefaultValueInstantiator(BasicDeserializerFactory.java:272)
    at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory.findValueInstantiator(BasicDeserializerFactory.java:223)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.buildBeanDeserializer(BeanDeserializerFactory.java:261)
    ... 12 more
  • Dependency:
         <dependency>
            <groupId>com.fasterxml.jackson.dataformat</groupId>
            <artifactId>jackson-dataformat-xml</artifactId>
            <version>2.11.1</version>
        </dependency>
cowtowncoder commented 1 year ago

Correct: this is not currently supported: attribute-ness is really only used for serialization but not used to distinguish source for incoming properties.

I will leave this open as a request to support such cases.

kalyansagi commented 1 year ago

@cowtowncoder Thanks for your response. How do I cross this bridge? Any other recommendations?

cowtowncoder commented 1 year ago

@kalyansagi Unfortunately I cannot think of many work-arounds. Theoretically I guess you could use readTree to get structure in which all data is retained (duplicates are actually supported, resulting in ArrayNodes), and then post-process content, but that would not retain attribute/element distinction.

mfg92 commented 1 year ago

I have a similar problem, the XML schema of the german electronic medication plan (eMP) contains an element MP which has an attribute U as well as child elements U. I'm using the jaxb2-maven-plugin (with some additional binding configuration) to generate the mapping Java classes. Unfortunately, neither the deserialization nor the serialization works and I get the same exception as the OP.

Support for such scenarios would be greatly appreciated.