问题描述
我有以下架构:
<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 returnorg.foo.bar.Unit
. - If I remove
<xsd:element name="unit" type="bar:unit" />
declaration, JAXB starts to returnorg.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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!