JAXB可以生成ArrayList而不是List吗?

时间:2011-01-25 07:32:27

标签: java collections jaxb arraylist

<complexType name="BookShelf">
   <sequence>
      <choice minOccurs="0" maxOccurs="unbounded">
         <element name="newBook" type="string"/>
         <element name="oldBook" type="string"/>
      </choice>
   </sequence>
</complexType>

JAXB将该属性生成为List<JAXBElement<String>>。有没有什么方法可以生成ArrayList?

3 个答案:

答案 0 :(得分:14)

为什么,那对你有什么好处?

  1. ArrayList<E>没有公开 不在的方法 List<E>接口,所以有 你无能为力 你无法做到的ArrayList<E> 与任何其他List<E>(实际上 有一个: ArrayList.trimToSize(), 谢谢@Joachim Sauer,但是 几乎没有必要)。
  2. API的实践很糟糕 接受或返回实施 类型而不是底层 接口。我建议你 按照Collections Trail Sun Java教程和/或阅读 Effective Java by Joshua Bloch (你会知道他是什么 谈论from this short preview,这是下面引用的来源),以了解更多关于 集合框架和接口 的使用。
  3. 谁说基础列表 实施不是ArrayListArrayList是最多的 常用的List实现 无论如何,所以很有可能 JAXB实际上会返回一个 ArrayList,它不会告诉你 所以(因为你不需要知道)。
  4. 项目52:通过其接口参考对象(摘录)

      

    第40项包含您的建议   应该使用接口而不是   类作为参数类型。更多   一般来说,你应该赞成使用   接口而不是类   指对象。 如果合适的话   那么接口类型就存在了   参数,返回值,变量,   和字段都应该声明   使用界面类型。唯一的时间   你真的需要参考一个   对象的类是在你创建的时候   它与构造函数。为了做到这一点   具体,考虑的情况   Vector,这是一个实现   List接口的。进入   打字的习惯:

    // Good - uses interface as type
    List<Subscriber> subscribers = new Vector<Subscriber>();
    
      

    而不是:

    // Bad - uses class as type!
    Vector<Subscriber> subscribers = new Vector<Subscriber>();
    

    [...]

    来源:有效的Java,preview on SafariBooksOnline

答案 1 :(得分:5)

默认情况下,该属性为List,底层实现为ArrayList。当然,您可以使用JAXB自定义来更改底层实现,或者使用自己的类具有ArrayList类型的属性(尽管出于其他答案中提到的原因,这很少是一个好主意)。

默认JAXB生成

给出您的XML Schema:

<schema xmlns="http://www.w3.org/2001/XMLSchema">
   <complexType name="BookShelf">
      <sequence>
         <choice minOccurs="0" maxOccurs="unbounded">
            <element name="newBook" type="string"/>
            <element name="oldBook" type="string"/>
         </choice>
      </sequence>
   </complexType>
</schema>

使用以下命令行:

xjc -d out your-schema.xsd

JAXB将生成以下类:

package generated;

import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlElementRefs;
import javax.xml.bind.annotation.XmlType;


@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "BookShelf", propOrder = {
    "newBookOrOldBook"
})
public class BookShelf {

    @XmlElementRefs({
        @XmlElementRef(name = "newBook", type = JAXBElement.class),
        @XmlElementRef(name = "oldBook", type = JAXBElement.class)
    })
    protected List<JAXBElement<String>> newBookOrOldBook;

    public List<JAXBElement<String>> getNewBookOrOldBook() {
        if (newBookOrOldBook == null) {
            newBookOrOldBook = new ArrayList<JAXBElement<String>>();
        }
        return this.newBookOrOldBook;
    }

}

自定义代

默认情况下,JAXB的属性类型为List,底层实现为ArrayList。如果您希望控制底层实现,可以使用外部绑定文件,如:

<jxb:bindings 
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
    version="2.1">

    <jxb:bindings schemaLocation="f3.xsd">
            <jxb:bindings node="//xs:complexType[@name='BookShelf']/xs:sequence/xs:choice">
                <jxb:property collectionType="java.util.LinkedList"/>
            </jxb:bindings>
    </jxb:bindings>

</jxb:bindings>

以下XJC致电:

xjc -d out -b binding.xml your-schema.xsd

改为获得以下课程:

package generated;

import java.util.LinkedList;
import java.util.List;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlElementRefs;
import javax.xml.bind.annotation.XmlType;


@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "BookShelf", propOrder = {
    "newBookOrOldBook"
})
public class BookShelf {

    @XmlElementRefs({
        @XmlElementRef(name = "oldBook", type = JAXBElement.class),
        @XmlElementRef(name = "newBook", type = JAXBElement.class)
    })
    protected List<JAXBElement<String>> newBookOrOldBook = new LinkedList<JAXBElement<String>>();

    public List<JAXBElement<String>> getNewBookOrOldBook() {
        if (newBookOrOldBook == null) {
            newBookOrOldBook = new LinkedList<JAXBElement<String>>();
        }
        return this.newBookOrOldBook;
    }

}

使用您自己的课程:

您也可以使用自己的类与ArrayList类型的属性(尽管出于其他答案中提到的原因,这很少是个好主意。)

package com.example;

import java.util.ArrayList;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlElementRefs;
import javax.xml.bind.annotation.XmlType;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "BookShelf", propOrder = {
    "newBookOrOldBook"
})
public class BookShelf {

    @XmlElementRefs({
        @XmlElementRef(name = "oldBook", type = JAXBElement.class),
        @XmlElementRef(name = "newBook", type = JAXBElement.class)
    })
    protected ArrayList<JAXBElement<String>> newBookOrOldBook ;

    public ArrayList<JAXBElement<String>> getNewBookOrOldBook() {
        if (newBookOrOldBook == null) {
            newBookOrOldBook = new ArrayList<JAXBElement<String>>();
        }
        return this.newBookOrOldBook;
    }

}

更多信息:

答案 2 :(得分:1)

您无法更改API生成列表的事实。

但是,假设底层实现实际上产生了一个ArrayList,你总是可以将它转换为ArrayList:

ArrayList<JAXBElement<String>> arrayList = 
        (ArrayList<JAXBElement<String>>) list;

或者,如果它不是一个arraylist(即你尝试上面的例外...),你可以生成一个包含相同列表元素的新ArrayList。

ArrayList<JAXBElement<String>> arrayList = 
        new ArrayList<JAXBElement<String>>(list);

但是,一般情况下,您不需要执行任何操作:只要可以,就可以更好地对接口抽象进行编码而不是基础具体类。