【问题标题】:JAXB avoid JAXBElement<?>JAXB 避免 JAXBElement<?>
【发布时间】:2014-03-19 17:32:31
【问题描述】:

我想从 XSD 文件生成带有 JAXB 的 Java 类。

问题是,我总是得到一些像这样的类(删除了命名空间):

public static class Action {

            @XmlElementRefs({
                @XmlElementRef(name = "ReportStateCanceled", namespace = "http://...", type = JAXBElement.class, required = false),
                @XmlElementRef(name = "ReportDate", namespace = "http://...", type = JAXBElement.class, required = false),
                @XmlElementRef(name = "ReportStatePreliminary", namespace = "http://...", type = JAXBElement.class, required = false),
                @XmlElementRef(name = "DocumentID", namespace = "http://...", type = JAXBElement.class, required = false),
                @XmlElementRef(name = "ReportStateNotValidated", namespace = "http://...", type = JAXBElement.class, required = false),
                @XmlElementRef(name = "CaseNo", namespace = "http://...", type = JAXBElement.class, required = false),
                @XmlElementRef(name = "PatientID", namespace = "http://...", type = JAXBElement.class, required = false),
                @XmlElementRef(name = "DocumentKey", namespace = "http://...", type = JAXBElement.class, required = false),
                @XmlElementRef(name = "ReportTime", namespace = "http://...", type = JAXBElement.class, required = false),
                @XmlElementRef(name = "ReportHeading", namespace = "http://...", type = JAXBElement.class, required = false),
                @XmlElementRef(name = "ReportStateComplete", namespace = "http://...", type = JAXBElement.class, required = false)
            })
            protected List<JAXBElement<?>> documentKeyOrDocumentIDOrPatientID;
            @XmlAttribute(name = "name")
            protected String name;
            @XmlAttribute(name = "Query")
            protected String query;

            /**
             * Gets the value of the documentKeyOrDocumentIDOrPatientID property.
             * 
             * <p>
             * This accessor method returns a reference to the live list,
             * not a snapshot. Therefore any modification you make to the
             * returned list will be present inside the JAXB object.
             * This is why there is not a <CODE>set</CODE> method for the documentKeyOrDocumentIDOrPatientID property.
             * 
             * <p>
             * For example, to add a new item, do as follows:
             * <pre>
             *    getDocumentKeyOrDocumentIDOrPatientID().add(newItem);
             * </pre>
             * 
             * 
             * <p>
             * Objects of the following type(s) are allowed in the list
             * {@link JAXBElement }{@code <}{@link Template.Page.Actions.Action.ReportDate }{@code >}
             * {@link JAXBElement }{@code <}{@link String }{@code >}
             * {@link JAXBElement }{@code <}{@link String }{@code >}
             * {@link JAXBElement }{@code <}{@link String }{@code >}
             * {@link JAXBElement }{@code <}{@link String }{@code >}
             * {@link JAXBElement }{@code <}{@link String }{@code >}
             * {@link JAXBElement }{@code <}{@link String }{@code >}
             * {@link JAXBElement }{@code <}{@link String }{@code >}
             * {@link JAXBElement }{@code <}{@link String }{@code >}
             * {@link JAXBElement }{@code <}{@link Template.Page.Actions.Action.ReportTime }{@code >}
             * {@link JAXBElement }{@code <}{@link String }{@code >}
             * 
             * 
             */
            public List<JAXBElement<?>> getDocumentKeyOrDocumentIDOrPatientID() {
                if (documentKeyOrDocumentIDOrPatientID == null) {
                    documentKeyOrDocumentIDOrPatientID = new ArrayList<JAXBElement<?>>();
                }
                return this.documentKeyOrDocumentIDOrPatientID;
            }

            /**
             * Gets the value of the name property.
             * 
             * @return
             *     possible object is
             *     {@link String }
             *     
             */
            public String getName() {
                return name;
            }

            /**
             * Sets the value of the name property.
             * 
             * @param value
             *     allowed object is
             *     {@link String }
             *     
             */
            public void setName(String value) {
                this.name = value;
            }

            /**
             * Gets the value of the query property.
             * 
             * @return
             *     possible object is
             *     {@link String }
             *     
             */
            public String getQuery() {
                return query;
            }

            /**
             * Sets the value of the query property.
             * 
             * @param value
             *     allowed object is
             *     {@link String }
             *     
             */
            public void setQuery(String value) {
                this.query = value;
            }


            /**
             * <p>Java class for anonymous complex type.
             * 
             * <p>The following schema fragment specifies the expected content contained within this class.
             * 
             * <pre>
             * &lt;complexType>
             *   &lt;simpleContent>
             *     &lt;extension base="&lt;http://www.w3.org/2001/XMLSchema>string">
             *       &lt;attribute name="dateFormat" type="{http://www.w3.org/2001/XMLSchema}string" />
             *     &lt;/extension>
             *   &lt;/simpleContent>
             * &lt;/complexType>
             * </pre>
             * 
             * 
             */
            @XmlAccessorType(XmlAccessType.FIELD)
            @XmlType(name = "", propOrder = {
                "value"
            })
            public static class ReportDate {

                @XmlValue
                protected String value;
                @XmlAttribute(name = "dateFormat")
                protected String dateFormat;

                /**
                 * Gets the value of the value property.
                 * 
                 * @return
                 *     possible object is
                 *     {@link String }
                 *     
                 */
                public String getValue() {
                    return value;
                }

                /**
                 * Sets the value of the value property.
                 * 
                 * @param value
                 *     allowed object is
                 *     {@link String }
                 *     
                 */
                public void setValue(String value) {
                    this.value = value;
                }

                /**
                 * Gets the value of the dateFormat property.
                 * 
                 * @return
                 *     possible object is
                 *     {@link String }
                 *     
                 */
                public String getDateFormat() {
                    return dateFormat;
                }

                /**
                 * Sets the value of the dateFormat property.
                 * 
                 * @param value
                 *     allowed object is
                 *     {@link String }
                 *     
                 */
                public void setDateFormat(String value) {
                    this.dateFormat = value;
                }

            }

如您所见,JAXB 使用 JAXBElement。这样的类对我来说是不可用的。


经过一番研究,我发现 JAXB 与 nillable="true" 和 minOccurs="0" 一起存在问题,但我没有在任何地方使用 nillable。我敢肯定,这个问题与minOccurs 和maxOccurs 有关。

即使我知道确切的问题,这也是个问题,因为我从外部人员那里获得了 XSD,并且不允许我对其进行修改。

XSD sn-p:

<xs:element name="Action" minOccurs="0" maxOccurs="unbounded">
    <xs:complexType>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
            <xs:element name="DocumentKey" type="xs:string" minOccurs="0" maxOccurs="1"/>
            <xs:element name="DocumentID" type="xs:string" minOccurs="0" maxOccurs="1"/>
            <xs:element name="PatientID" type="xs:string" minOccurs="0" maxOccurs="1"/>
            <xs:element name="CaseNo" type="xs:string" minOccurs="0" maxOccurs="1"/>
            <xs:element name="ReportHeading" type="xs:string" minOccurs="0" maxOccurs="1"/>
            <xs:element name="ReportDate" minOccurs="0" maxOccurs="1">
                <xs:complexType>
                    <xs:simpleContent>
                        <xs:extension base="xs:string" >
                            <xs:attribute name="dateFormat" type="xs:string" />
                        </xs:extension>
                    </xs:simpleContent>
                </xs:complexType>
            </xs:element>
            <xs:element name="ReportTime" minOccurs="0" maxOccurs="1">
                <xs:complexType>
                    <xs:simpleContent>
                        <xs:extension base="xs:string" >
                            <xs:attribute name="timeFormat" type="xs:string" />
                        </xs:extension>
                    </xs:simpleContent>
                </xs:complexType>
            </xs:element>
            <xs:element name="ReportStateNotValidated" type="xs:string" minOccurs="0" maxOccurs="1"/>
            <xs:element name="ReportStatePreliminary" type="xs:string" minOccurs="0" maxOccurs="1"/>
            <xs:element name="ReportStateComplete" type="xs:string" minOccurs="0" maxOccurs="1"/>
            <xs:element name="ReportStateCanceled" type="xs:string" minOccurs="0" maxOccurs="1"/>
        </xs:choice>
        <xs:attribute name="name" type="xs:string" />
        <xs:attribute name="Query" type="xs:string" />
    </xs:complexType>
</xs:element>

所以我寻找另一种解决方案。 我总是得出的结论是,如果在从 XSD 生成类时添加 jaxb-binding.xml,我可以解决问题。

我尝试了一些绑定,但都没有成功。

使用此绑定,我得到的 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" generateElementProperty="false" >
                    <xjc:simple />
                </jaxb:globalBindings>
            </xs:appinfo>
        </xs:annotation>
    </xs:schema>

现在我问是否有人知道解决方案? 最好的解决方案是,如果有人为我提供了一个有效的 jaxb-binding.xml。

我使用的是 xjc 编译器的 2.2.4-2 版本。

提前谢谢你!

【问题讨论】:

  • 由于 XML Schema 中的 choice 结构,您将获得 @XmlElementRefs。
  • 感谢您的快速答复!我该如何解决这个问题?我不允许修改 XSD。
  • 我已经添加了答案:stackoverflow.com/a/22514164/383861

标签: jaxb xsd jaxbelement


【解决方案1】:

我专门为这个问题写了Simpify plugin。

<xs:schema ...
    xmlns:simplify="http://jaxb2-commons.dev.java.net/basic/simplify"
    jaxb:extensionBindingPrefixes="... simplify">

<xs:complexType name="typeWithReferencesProperty">
    <xs:choice maxOccurs="unbounded">
        <xs:element name="a" type="someType">
            <xs:annotation>
                <xs:appinfo>
                    <simplify:as-element-property/>
                </xs:appinfo>
            </xs:annotation>
        </xs:element>
        <xs:element name="b" type="someType"/>
    </xs:choice> 
</xs:complexType>

会给你

@XmlElement(name = "a")
protected List<SomeType> a;
@XmlElement(name = "b")
protected List<SomeType> b;

而不是

@XmlElementRefs({
    @XmlElementRef(name = "a", type = JAXBElement.class),
    @XmlElementRef(name = "b", type = JAXBElement.class)
})
protected List<JAXBElement<SomeType>> aOrB;

免责声明:我是作者。

【讨论】:

  • @lexicore 我正在使用你的 jaxb2-annotate-plugin(好东西!),我正在尝试为这个场景添加简化插件。但是当我将 jaxb2-basics-0.12.1-SNAPSHOT.jar 添加到类路径时,xjc 抱怨“无法识别的参数 -Xannotate”。有什么想法吗?
  • @linus 请参阅github.com/highsource/jaxb2-annotate-plugin 或提出单独的问题。
【解决方案2】:

问题

问题是你的xs:choice 元素有maxOccurs="unbounded"。

<xs:choice minOccurs="0" maxOccurs="unbounded">

JAXB 规范参考

因为这个 JAXB 不能为选择结构中的每个选项生成单独的属性。有关详细信息,请参阅 JAXB 2.2 (JSR-222) 规范的“6.12.6 绑定重复出现模型组”:

为什么会出现问题

以下 XML 片段根据您的 XML 架构是有效的,并且需要能够在生成的对象模型中表示。

<Action>
    <DocumentID/>
    <PatientID/>
    <PatientID/>
    <DocumentID/>
</Action>

解决方法

如果您真的不喜欢 JAXB 生成的类,您可以创建自己的类,并通过绑定文件指定 JAXB 应该使用它而不是创建新类。

<jxb:bindings schemaLocation="yourSchema.xsd">
    <jxb:bindings node="//xs:element[@name='Action']">
        <jxb:class ref="com.example.Action"/>
    </jxb:bindings>
</jxb:bindings>

【讨论】:

  • 我试过用这种方式解决它,但我没有成功。 绑定: &lt;jxb:bindings version="2.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb" xmlns:xs="http://www.w3.org/2001/XMLSchema"&gt; &lt;jxb:bindings &lt;jxb:bindings node="//xs:element[@name='Action']"&gt; &lt;jxb:class ref="com.example.Action"/&gt; &lt;/jxb:bindings&gt; &lt;/jxb:bindings &lt;/jxb:bindings&gt; 错误: [ERROR] XPath evaluation of "//xs:element[@name='Action']" results in empty target node 有什么想法吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多