【问题标题】:Why does JAXB sometimes map to JAXBElement?为什么 JAXB 有时会映射到 JAXBElement?
【发布时间】:2010-09-07 11:51:14
【问题描述】:

the unofficial guide 上有一个占位符答案,其中包含指向(对我而言)似乎完全无关的文章的链接。

我使用 XJC 生成我的 JAXB 类,虽然它们中的大多数按预期相互映射,但有些元素被映射到 JAXBElement<Foo>。这对于带有循环的图来说是最烦人的,有时 Foo 元素的父节点将是 JAXBElement<Foo>,它本身没有父属性,从而打破了循环。

我可以想到各种解决方法,但如果有人可以向我解释这种行为会更好。为什么 JAXB 有时会将 <Foo> 元素映射到 JAXBElement<Foo> 而不是 Foo?

【问题讨论】:

  • @skaffman:嗯?我看不出您的回答与 xjc 是否选择 JAXBElement<Foo> 而不是 Foo 有什么关系。
  • @Chris:因为它部分取决于源模式中匿名类型或名称类型的选择。

标签: java jaxb jaxb2


【解决方案1】:

JAXBElement 用于在对象模型中没有足够信息的用例中保留元素名称/命名空间。最常见的情况是替换组:

有替换组:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    targetNamespace="http://www.example.org" 
    xmlns="http://www.example.org" 
    elementFormDefault="qualified">

    <xs:element name="root">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="anElement"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:element name="anElement" type="xs:string"/>

    <xs:element name="aSubstituteElement" type="xs:string" substitutionGroup="anElement"/>

</xs:schema>

将生成:

package org.example;

import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "anElement"
})
@XmlRootElement(name = "root")
public class Root {

    @XmlElementRef(name = "anElement", namespace = "http://www.example.org", type = JAXBElement.class)
    protected JAXBElement<String> anElement;

    public JAXBElement<String> getAnElement() {
        return anElement;
    }

    public void setAnElement(JAXBElement<String> value) {
        this.anElement = ((JAXBElement<String> ) value);
    }

}

无替换组:

如果您删除替换组:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    targetNamespace="http://www.example.org" 
    xmlns="http://www.example.org" 
    elementFormDefault="qualified">

    <xs:element name="root">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="anElement"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:element name="anElement" type="xs:string"/>

</xs:schema>

将生成以下类:

package org.example;

import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "anElement"
})
@XmlRootElement(name = "root")
public class Root {

    @XmlElement(required = true)
    protected String anElement;

    public String getAnElement() {
        return anElement;
    }

    public void setAnElement(String value) {
        this.anElement = value;
    }

}

你也可能在解组时得到一个 JAXBElement,比较下面的例子:

【讨论】:

  • 谢谢,替换组确实是发生这种情况的地方。那么,在afterUnmarshal(Unmarshaller u, Object parent) 中,这些可替代的类被作为parent 传递它们自己的JAXBElement 是不是一个错误?特别是因为似乎没有办法从 JAXBElement 获取真正的父元素。
  • 这似乎是 Metro JAXB(参考实现,包含在 Java SE 6 中)中的一个错误。在 MOXy JAXB 实现 (eclipse.org/eclipselink/moxy.php) 中,正确的父对象被传递给 afterUnmarshal 方法。
【解决方案2】:

要避免映射到 JAXBElement? 我已经完成了对我有用的事情:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
           xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
           jaxb:extensionBindingPrefixes="xjc"
           jaxb:version="2.0">

    <xs:annotation>
       <xs:appinfo>
          <jaxb:globalBindings generateValueClass="false">
           <xjc:simple />
          </jaxb:globalBindings>
       </xs:appinfo>
    </xs:annotation>

</xs:schema>

将此文件保存在 xml 文件中并作为绑定文件提供。

参考Link

使用 Eclipse 生成 JAXB 类不要忘记提供使用上述 xml 创建的绑定文件并检查“允许供应商扩展”如下:

通过更改,我可以摆脱生成 xjc 的类中的 JAXBElement,以便将 xsd 转换为 JAXB 生成的类。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-10-10
    • 1970-01-01
    • 2016-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-19
    相关资源
    最近更新 更多