为什么JAXB不为列表生成setter

Ahm*_*leh 56 java jaxb getter-setter

当我从XSD生成JAXB类时,元素maxOccurs="unbounded"会为它们生成一个getter方法,但是没有setter方法,如下所示:

/**
 * Gets the value of the element3 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 element3 property.
 * 
 * <p>
 * For example, to add a new item, do as follows:
 * <pre>
 *    getElement3().add(newItem);
 * </pre>
 * 
 * 
 * <p>
 * Objects of the following type(s) are allowed in the list
 * {@link Type }
 * 
 * 
 */
public List<Type> getElement3() {
    if (element3 == null) {
        element3 = new ArrayList<Type>();
    }
    return this.element3;
}
Run Code Online (Sandbox Code Playgroud)

方法注释使我可以清楚地知道如何使用它,但我的问题如下:
为什么JAXB不遵循Java Beans规则生成一个setter?我知道我可以自己编写setter方法,但生成的getter方法中建议的方法有什么优势吗?

这是我的XSD:

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

    <element name="CollectionTest" type="tns:CollectionTest"></element>

    <complexType name="CollectionTest">
        <sequence>
            <element name="element1" type="string" maxOccurs="1" minOccurs="1"></element>
            <element name="element2" type="boolean" maxOccurs="1" minOccurs="1"></element>
            <element name="element3" type="tns:type" maxOccurs="unbounded" minOccurs="1" nillable="true"></element>
        </sequence>
    </complexType>


    <complexType name="type">
        <sequence>
            <element name="subelement1" type="string" maxOccurs="1" minOccurs="1"></element>
            <element name="subelement2" type="string" maxOccurs="1" minOccurs="0"></element>
        </sequence>
    </complexType>
</schema>
Run Code Online (Sandbox Code Playgroud)

jde*_*sey 28

以下是JAXB规范的理由 - 第60页.

设计说明 - List属性没有setter方法.getter通过引用返回List.可以使用java.util.List上定义的适当方法将项添加到getter方法返回的List中.JAXB 1.0中此设计的基本原理是使实现能够包装列表,并能够在列表中添加或删除内容时执行检查.

因此,如果List的实现覆盖了add/remove来执行验证,则将(例如)ArrayList替换为"special"List会使这些检查无效.

  • 坦率地说,我认为这严重违反了Java bean的工作方式.当JAXB看到一个没有setter的bean属性返回的集合时,我会很好地调用.add().但是,如果我定义了一个setter,它真的应该假设我已经完成了一个原因并且该死的期望它没有被绕过,有时我甚至会返回不可修改的收集包装,迫使人们不要搞砸我的内部.抱歉咆哮,但这个bug已经浪费了两天的时间. (8认同)
  • 不幸的是,没有setter,像BlazeDS这样的其他组件将不会将`getItems()`识别为属性的一部分,并且将回退到字段名称(受保护)并最终传递null,无论列表中的内容如何.添加setter(调用getItems,清除它并添加新值)可以解决此问题. (4认同)

Nar*_*hai 26

链接:没有列表的setter

getter方法中的代码确保创建List.没有相应的setter,这意味着列表元素的所有添加或删除都必须在"实时" 列表中进行.

正如引用所说,没有像使用getter方法那样的setter,它确保如果不存在则初始化列表的新实例.

之后,当你必须添加或删除任何你必须使用的东西时

getElement3().add(Type);
Run Code Online (Sandbox Code Playgroud)

更新:编组null和空列表的差异

列表的示例 null

@XmlRootElement(name = "list-demo")
public class ListDemo {

    @XmlElementWrapper(name = "list")
    @XmlElement(name = "list-item")
    private List<String> list;

}
Run Code Online (Sandbox Code Playgroud)

输出将是

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<list-demo/>
Run Code Online (Sandbox Code Playgroud)

列表为空的示例

@XmlRootElement(name = "list-demo")
public class ListDemo {

    @XmlElementWrapper(name = "list")
    @XmlElement(name = "list-item")
    private List<String> list = new ArrayList<String>();

}
Run Code Online (Sandbox Code Playgroud)

输出将是:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<list-demo>
    <list/>
</list-demo>
Run Code Online (Sandbox Code Playgroud)

  • 我仍然不明白为什么JAXB会关心**确保列表的新实例如果不存在则被初始化**!!! 为什么它会关心,如果列表值为"null"或空列表,JAXB的工作方式完全相同.并且防止`NullPointerException在这里超出了JAXB范围IMO. (4认同)
  • 我明白了,`@ XmlElementWrapper`就行了.但是,默认情况下JAXB不会生成它,实际上默认情况下它也使用字段访问类型,因此初始化getter中的列表不会影响编组...我的观点是关于通过不生成a来打破Java Bean规则二传手 (3认同)

小智 5

同意上面帕特里克的担忧。如果我直接对生成的 java 类进行编码,我很乐意帮忙,但我使用的内省工具需要 setter 或直接访问的成员。已成功使用来自https://github.com/highsource/jaxb2-basics/wiki/JAXB2-Setters-Plugin的 XJC 插件 并向 wsimport 添加 -B-Xsetter 参数