本文介绍了如何重构XSD以便解组不返回JAXBElement的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下架构:

<xsd:schema xmlns:bar="http://www.foo.org/bar"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:annox="http://annox.dev.java.net"
        xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
        targetNamespace="http://www.foo.org/bar"
        jaxb:extensionBindingPrefixes="annox" jaxb:version="2.1" elementFormDefault="qualified">

    <xsd:element name="unit" type="bar:unit" />

    <xsd:complexType name="unit">
        <xsd:annotation>
            <xsd:appinfo>
                <annox:annotate>@javax.xml.bind.annotation.XmlRootElement(name="unit")</annox:annotate>
            </xsd:appinfo>
        </xsd:annotation>
            <xsd:sequence>
            <xsd:any processContents="skip" />
        </xsd:sequence>
    </xsd:complexType>

</xsd:schema>

当我解组这个XML时

<unit xmlns="http://www.foo.org/bar">
    <text>Name</text>
</unit>

返回的对象是 javax.xml.bind.JAXBElement< Unit> ,但是我想得到 org.foo.bar.Unit 。我需要这个,因为在我的情况下解组是由JAX-RS提供者或SpringWeb隐式发生的。

the returned object is javax.xml.bind.JAXBElement<Unit>, however I would like to get org.foo.bar.Unit back. I need this because unmarshalling in my case happens implicitly by JAX-RS provider or SpringWeb.

观察:


  • 如果我删除/替换< xsd:any processContents =skip/> 声明,JAXB开始返回 org.foo.bar.Unit

  • 如果我删除< xsd:element name =unittype =bar:单元/> 声明,JAXB开始返回 org.foo.bar.Unit (尽管需要在解组时禁用验证)。

  • If I remove/replace <xsd:any processContents="skip" /> declaration, JAXB starts to return org.foo.bar.Unit.
  • If I remove <xsd:element name="unit" type="bar:unit" /> declaration, JAXB starts to return org.foo.bar.Unit (although one need to disable validation during unmarshalling).

因此我会说,给定XSD是证明问题的最小XSD。

Thus I would say that given XSD is the smallest XSD that demonstrates the problem.

问题:为什么JAXB将 org.foo.bar.Unit 包装到上面的组合中的 JAXBElement ?从我看到的情况来看,XSD类型 unit 无法使标签名称与 unit 不同,所以为什么选择JAXB需要这种工厂方法吗?

Questions: Why JAXB wraps org.foo.bar.Unit into JAXBElement for above combination? From what I see, there is no way the XSD type unit can have tag name different from unit, so why JAXB needs this factory method?

@XmlElementDecl(namespace = "http://www.foo.org/bar", name = "unit")
public JAXBElement<Unit> createUnit(Unit value) { ... }

证明JAXB 2.2.7问题的项目是。运行时输出以下内容:

The project demonstrating the problem for JAXB 2.2.7 is here. When run it outputs the following:

Running org.foo.bar.UnitTest
>>> Class is: javax.xml.bind.JAXBElement
>>> XML is: <?xml version="1.0" encoding="UTF-8" standalone="yes"?><unit xmlns="http://www.foo.org/bar"><text>Name</text></unit>
Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.318 sec <<< FAILURE!


推荐答案

添加到Ian的答案,
任何 root 元素命名的code>复杂元素将使用 @XmlElementDecl()。

Adding to Ian's answer,Any complex element that is named by root element will have factory method annotated with @XmlElementDecl().

您可以通过内联移动复杂类型声明来解决此问题,如下所示。

You can resolve this, by moving the complex type declaration inline like below.

<xsd:schema xmlns= "http://www.foo.org/bar" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:annox="http://annox.dev.java.net" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
    targetNamespace="http://www.foo.org/bar" jaxb:extensionBindingPrefixes="annox"
    jaxb:version="2.1" elementFormDefault="qualified">
    <xsd:element name="unit">
        <xsd:complexType>
            <xsd:annotation>
                <xsd:appinfo>
                    <annox:annotate>@javax.xml.bind.annotation.XmlRootElement(name="unit")
                    </annox:annotate>
                </xsd:appinfo>
            </xsd:annotation>
            <xsd:sequence>
                <xsd:any processContents="skip" />
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>
</xsd:schema>

ObjectFactory.class (没有 JAXBElement 这里生成的工厂方法)

ObjectFactory.class (no JAXBElement factory method generated here)

@XmlRegistry
public class ObjectFactory {


    /**
     * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: org.foo.bar
     * 
     */
    public ObjectFactory() {
    }

    /**
     * Create an instance of {@link Unit }
     * 
     */
    public Unit createUnit() {
        return new Unit();
    }

}

测试类:

@Test
public void testUnmarshalling() throws JAXBException, SAXException {
    JAXBContext context = JAXBContext.newInstance(Unit.class);

    Unmarshaller unmarshaller = context.createUnmarshaller();

    unmarshaller.setSchema(SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI)
            .newSchema(new StreamSource(getClass().getClassLoader().getResourceAsStream("common.xsd"))));

    Object unit = unmarshaller.unmarshal(getClass().getResourceAsStream("unit.xml"));

    System.out.println(">>> Class is: " + unit.getClass().getName());

    StringWriter writer = new StringWriter();
    context.createMarshaller().marshal(unit, writer);

    System.out.println(">>> XML is: " + writer.toString());

    //assertTrue(unit instanceof Unit);
}

测试xml:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<unit xmlns="http://www.foo.org/bar">
    <text>Name</text>
</unit>

输出

>>> Class is: org.foo.bar.Unit
>>> XML is: <?xml version="1.0" encoding="UTF-8" standalone="yes"?><unit xmlns="http://www.foo.org/bar"><text>Name</text></unit>

这篇关于如何重构XSD以便解组不返回JAXBElement的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-18 19:53