Arun Mascarenhas
Arun Mascarenhas

Reputation: 1

Jackson throws an UnrecognizedPropertyException when deserializing JAXB generated classes

I am working with a third-party service that has provided us with an XSD, and I use a maven plugin (maven-jaxb2-plugin) to generate the corresponding java classes.

Using the JAXB Unmarshaller, I can deserialize the responses from the third-party service. However, due to constraints on the target execution environment, I cannot use the JAXB Unmarshaller - so I settled on using Jackson (jackson-dataformat-xml). However, I cannot get Jackson to deserialize the responses from the third-party service. I have provided representative samples of the XSD, generated code, and usage code below.

What I have tried so far:

What I have not tried:

I suspect that Jackson does not like the nested xs:choice tags, but I do not know for sure - I will investigate that soon and post my findings on here, if any.

XSD:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
    <xs:element name="element1">
        <xs:complexType>
            <xs:choice maxOccurs="unbounded">
                <xs:element name="element1_1">
                    <xs:complexType>
                        <xs:simpleContent>
                            <xs:extension base="xs:string">
                                <xs:attribute name="attribute1">
                                    <xs:simpleType>
                                        <xs:restriction base="xs:string">
                                            <xs:enumeration value="aa"/>
                                            <xs:enumeration value="de"/>
                                            <xs:enumeration value="en"/>
                                        </xs:restriction>
                                    </xs:simpleType>
                                </xs:attribute>
                                <xs:attribute name="attribute2" use="optional" />
                            </xs:extension>
                        </xs:simpleContent>
                    </xs:complexType>
                </xs:element>
                <xs:choice minOccurs="0">
                    <xs:element ref="element2"/>
                    <xs:element name="element1_2" type="xs:string"/>
                </xs:choice>
                <xs:element ref="element3" minOccurs="0"/>
                <xs:element name="element1_3" type="xs:dateTime" minOccurs="0"/>
                <xs:element name="element1_4" type="xs:string" nillable="true" minOccurs="0"/>
            </xs:choice>
        </xs:complexType>
    </xs:element>
    <xs:element name="element2">
        <xs:complexType>
            <xs:choice minOccurs="0" maxOccurs="unbounded">
                <xs:element ref="element4" minOccurs="0" maxOccurs="unbounded"/>
            </xs:choice>
        </xs:complexType>
    </xs:element>
    ...
</xs:schema>

JAXB Generated Class:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "element1_1OrElement2OrElement1_2"
})
@XmlRootElement(name = "ContentObject")
public class Element1 {

    @XmlElements({
        @XmlElement(name = "element1_1", type = JAXBElement.class, required = false),
        @XmlElement(name = "element2", type = Element2.class, required = false),
        @XmlElement(name = "element1_2", type = JAXBElement.class, required = false),
        @XmlElement(name = "element3", type = Element3.class, required = false),
        @XmlElement(name = "element1_3", type = JAXBElement.class, required = false),
        ...
    })
    protected List<Object> element1_1OrElement2OrElement1_2;

    ...

    public List<Object> getElement1_1OrElement2OrElement1_2() {
        if (element1_1OrElement2OrElement1_2 == null) {
            element1_1OrElement2OrElement1_2 = new ArrayList<Object>();
        }
        return this.element1_1OrElement2OrElement1_2;
    }

    ...

}

JUnit Test: The CustomeDeserializer can be ignored - it did not make any difference.

package my.project.webservice;

import java.io.IOException;
import java.io.InputStream;

import javax.xml.bind.JAXBElement;

import org.junit.Test;
import org.w3c.dom.Document;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.jaxb.XmlJaxbAnnotationIntrospector;
import my.project.converter.ConverterException;
import my.project.converter.DocumentToStringConverter;
import my.project.converter.InputStreamToDocumentConverter;
import my.project.jaxb.CustomSerializer;
import my.project.jaxb.JaxbElementMixin;
import my.project.generated.GeneratedClass;

public class JacksonMapperTest {

    @Test
    public void test() {
        try {
            SimpleModule module = new SimpleModule("customeSerializerModule", new Version(1, 0, 0, null));
            module.addSerializer(JAXBElement.class, new CustomSerializer());

            XmlMapper m = new XmlMapper();
            m.setAnnotationIntrospector(new XmlJaxbAnnotationIntrospector (m.getTypeFactory()));
            m.addMixIn(JAXBElement.class, JaxbElementMixin.class);
            m.registerModule(module);

            InputStream is = this.getClass().getResourceAsStream("/stubbed-response.xml");
            Document doc = new InputStreamToDocumentConverter().convert(is);
            String xml = new DocumentToStringConverter().convert(doc);
            GeneratedClass c = m.readValue(xml, GeneratedClass.class);

        } catch (ConverterException e) {
            e.printStackTrace();
        } catch (JsonParseException e) {
            e.printStackTrace();
        } catch (JsonMappingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

Stack Trace:

com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "element2" (class my.project.models.xjb.Element1), not marked as ignorable (15 known properties: "element1_1OrElement2OrElement3", "element1_3", ...])
 at [Source: java.io.StringReader@6b419da; line: 3, column: 39] (through reference chain: my.project.generated.Element1["element2"]->java.util.ArrayList[0]->my.project.generated.Element1["element2"])
    at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:51)
    at com.fasterxml.jackson.databind.DeserializationContext.reportUnknownProperty(DeserializationContext.java:817)
    at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:954)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1315)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1293)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:249)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:136)
    at com.fasterxml.jackson.dataformat.xml.deser.WrapperHandlingDeserializer.deserialize(WrapperHandlingDeserializer.java:109)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:240)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:212)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:25)
    at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:523)
    at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:101)
    at com.fasterxml.jackson.databind.deser.impl.BeanPropertyMap.findDeserializeAndSet(BeanPropertyMap.java:285)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:248)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:136)
    at com.fasterxml.jackson.dataformat.xml.deser.WrapperHandlingDeserializer.deserialize(WrapperHandlingDeserializer.java:109)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3560)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2576)
    at my.project.webservice.JacksonMapperTest.test(JacksonMapperTest.java:40)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at mockit.integration.junit4.internal.JUnit4TestRunnerDecorator.executeTestMethod(JUnit4TestRunnerDecorator.java:131)
    at mockit.integration.junit4.internal.JUnit4TestRunnerDecorator.invokeExplosively(JUnit4TestRunnerDecorator.java:71)
    at mockit.integration.junit4.internal.MockFrameworkMethod.invokeExplosively(MockFrameworkMethod.java:42)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at mockit.internal.util.MethodReflection.invokeWithCheckedThrows(MethodReflection.java:112)
    at mockit.internal.mockups.MockMethodBridge.callMock(MockMethodBridge.java:85)
    at mockit.internal.mockups.MockMethodBridge.invoke(MockMethodBridge.java:44)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

Upvotes: 0

Views: 1914

Answers (1)

Sushant Tambare
Sushant Tambare

Reputation: 526

Use this:

objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);

Here example: http://wiki.fasterxml.com/JacksonHowToIgnoreUnknown

Upvotes: -1

Related Questions