【问题标题】:Jackson throws an UnrecognizedPropertyException when deserializing JAXB generated classesJackson 在反序列化 JAXB 生成的类时抛出 UnrecognizedPropertyException
【发布时间】:2015-04-06 06:27:37
【问题描述】:

我正在使用为我们提供 XSD 的第三方服务,并且我使用 maven 插件 (maven-jaxb2-plugin) 来生成相应的 java 类。

使用 JAXB Unmarshaller,我可以反序列化来自第三方服务的响应。但是,由于目标执行环境的限制,我不能使用 JAXB Unmarshaller - 所以我决定使用 Jackson (jackson-dataformat-xml)。但是,我无法让 Jackson 反序列化来自第三方服务的响应。我在下面提供了 XSD 的代表性示例、生成的代码和使用代码。

到目前为止我所做的尝试:

我没有尝试过的:

  • 修改生成的代码:如果 XSD 发生变化,我不想重新做任何工作。如果我能确定它会奏效,这将是最后的手段。
  • 每个 XSD 的手动编码类:同上,XSD 相当大,有很多对象。这将是最后的手段。

我怀疑 Jackson 不喜欢嵌套的 xs:choice 标签,但我不确定 - 我会尽快调查并在此处发布我的发现(如果有)。

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 生成类:

@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 测试: 可以忽略 CustomeDeserializer - 它没有任何区别。

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();
        }
    }

}

堆栈跟踪:

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)

【问题讨论】:

标签: java xml jaxb jackson


【解决方案1】:

使用这个:

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

此处示例:http://wiki.fasterxml.com/JacksonHowToIgnoreUnknown

【讨论】:

  • 不幸的是,这不起作用。反序列化的对象有许多为空的字段 - 我需要根据响应填充整个对象。
  • 未知属性是未在 XSD 中定义且未知的属性。它的setter方法也没有定义。因此,这个问题来了是我的理解。正确的?因此,如果这是正确的,那么我认为 null 字段与 XSD 中未知的字段不同。
  • 如果我没有在我的问题中明确指出,我很抱歉。但是该属性是在 XSD 中定义的,相应的 setter 在 XJC 生成的类中可用。但是,setter 名称的格式为 setAOrBOrC,因为缺少的字段是 XSD 中 xs:choice 类型中的一个选项。另外,我可以使用 JAXB 反序列化。是杰克逊不起作用。
猜你喜欢
  • 2019-11-20
  • 1970-01-01
  • 1970-01-01
  • 2022-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-22
相关资源
最近更新 更多