JAXB

简介

JAXB(Java Architecture for XML Binding)是一个业界的标准,是一项可以根据XML Schema产生Java类的技术。该过程中,JAXB也提供了将XML实例文档反向生成Java对象树的方法,并能将Java对象树的内容重新写到XML实例文档。

从另一方面来讲,JAXB提供了快速而简便的方法将XML模式绑定到Java表示,从而使得Java开发者在Java应用程序中能方便地结合XML数据和处理函数。

 

常用注解

先举个栗子:

public class JAXBTest {
    @Test
    public void generateXML() {
        Person person = new Person("abc", "男", "北京", "朝阳区");
        File file = new File("E:\\person.xml");
        JAXB.marshal(person, file);
    }
    @Test
    public void generateBean() {
        File file = new File("E:\\person.xml");
        Person person = JAXB.unmarshal(file, Person.class);
        System.out.println(person);
    }
}

[email protected]

作用和用法:

类级别的注解,将类映射为xml全局元素,也就是根元素。将该注解用在了person类上,则生成了<person>根元素,常与@XmlType,@XmlAccessorType,@XmlAccessorOrder连用。

属性:

name属性:用于指定生成元素的名字,若不指定则默认使用类名小写作为元素名
namespace属性:用于指定生成的元素所属的命名空间

修改上面的例子,在该注解上使用name属性:

@XmlRootElement(name = "human")
public class Person {
    private int id;
    private String name;
    ...
}    //省略下面代码

生成的xml:

JAXB

[email protected] 

作用和用法:

字段和方法级别的注解。该注解会将字段或get/set方法对应的字段映射成本类对应元素的属性。属性名默认使用字段名或get/set方法去掉前缀剩下部分首字母小写。

属性:该注解有name(指定生成元素的名字),required,namespace三个属性。用法和@XmlElement注解相同,如下:

@XmlAttribute(name = "ITSVersion", required = true)
    public String getItsVersion() {
        return itsVersion;
    }

修改上面栗子:

@XmlAttribute
public void setGender(String gender) {
    this.gender = gender;
}

生成的xml:属性名为gender

JAXB

对应的xsd:

  <xs:element name="human">
    <xs:complexType>
      <xs:sequence>
        <xs:element type="xs:string" name="addr"/>
        <xs:element type="xs:string" name="area"/>
        <xs:element type="xs:byte" name="id"/>
        <xs:element type="xs:string" name="name"/>
      </xs:sequence>
      <xs:attribute type="xs:string" name="gender"/>
    </xs:complexType>
  </xs:element>

[email protected] 

作用和用法:

字段,方法,参数级别的注解。该注解可以将被注解的字段(非静态),或者被注解的get/set方法对应的字段映射为本地元素,也就是子元素。默认使用字段名或get/set方法去掉前缀剩下部分小写作为元素名,栗子中,id、addr、name、gender、area都被映射成了<person>元素的子元素。

属性:

name属性可以指定生成元素的名字,同@XmlRootElement注解的name属性一样
nillable属性可以指定元素的文本值是否可以为空,默认为false。如下:

@XmlElement(nillable = true)
    public void setName(String name) {
    this.name = name;
}

则生成的xsd(为了节省篇幅,只截取必要的片段)为:

<xs:element name="name" type="xs:string" nillable="true" minOccurs="0"/> 

required属性可以指定该元素是否必须出现,默认为false,所以在xsd中会有对应的属性minOccurs="0"。修改该属性为true:

@XmlElement(nillable = true, required = true)
    public void setName(String name) {
    this.name = name;
}

生成的xsd文件为:

<xs:element name="name" type="xs:string" nillable="true" minOccurs="1"/> 

namespace属性可以指定该元素所属的命名空间

defaultValue属性可以指定该元素默认的文本值

[email protected] 

作用和用法:

类,字段,方法级别的注解。可使JAXB在映射xml元素时忽略被注解的类,字段,get/set对应字段。需要注意的是该注解与所有其他JAXB注释相互排斥,也就是说与其他注释连用就会报错。

属性:无属性

修改上面例子:

@XmlTransient
public void setId(int id) {
    this.id = id;
}

 生成的xml:

JAXB

[email protected] 

作用和用法:

包和类级别的注解。控制字段是否被默认序列化。就是决定哪些字段或哪些get/set方法对应的字段会被映射为xml元素,需要注意的是字段或get/set方法的访问权限(public/private)会影响字段是否被映射为xml元素

属性:该注解只有一个value属性,可取的值是一个名为XmlAccessType的枚举类型里的值

XmlAccessType.PROPERTY:

1.当使用了该值,只要字段有对应的get/set方法对(注意是成对出现,只有其中一个不会发生映射),不需要使用@XmlElement注解,不论该方法的访问权限是什么(即使是private),jaxb就会将该字段映射成xml元素。不过最好加上@XmlElement注解,get/set方法任选一个即可,都加上会报错。

2.若在一个字段有set/get方法对但又在字段上添加@XmlElement注解会报属性重复的错误。

3.若没有set/get方法对,则需要在字段上使用@XmlElement注解才可以映射为xml元素,否则不会发生映射。

4.若get/set方法上使用了@XmlTransient注解,但想要对应字段发生映射,需要在对应字段上添加@XmlElement注解,此时不会报错,并将该字段映射为xml元素。

XmlAccessType.FIELD:

1.每个非静态的字段(无论访问权限如何)都会被jaxb映射为xml元素,即使没有get/set方法对,即使没有使用@XmlElement元素,但最好加上该注解以表明该字段要被映射为xml元素。

2.虽然没有get/set方法对,也会发生映射,但加上get/set方法对也不会报错,因为我们经常会使用这两个方法。但注意,不能再在这两个方法上使用@XmlElement方法,否则会报属性重复的错误。

3.若在字段上使用了@XmlTransient注解,但还想让该字段发生映射,需要在该字段对应的get/set方法上添加@XmlElement

XmlAccessType.PUBLIC_MEMBER (该值为默认值):

官方解释:

1.每个访问权限为public的字段,或者每个访问权限为public的get/set方法对,都会将字段映射为xml元素,即使不使用@XmlElement,但最好加上。不可同时存在public字段和对应的get/set方法对,不然会报属性重复的错误。

2.若使用@XmlElement注解,需要注意只能在字段或get/set方法添加,两者任选其一,否则会报属性重复的错误。

3.若字段不为public,get/set方法为public并使用了@XmlTransient,需要在字段上添加@XmlElement才会发生映射。

若字段为public并使用了@XmlTransient,get/set方法对不为public,需要在get/set方法上使用@XmlElement才会映射。

XmlAccessType.NONE:

任何字段,get/set方法对都不会发生映射,除非使用某些注解,如@XmlElement,@XmlElementWrapper等。

[email protected]

作用和用法:包和类级别的注解。控制生成元素的顺序。

属性:只有一个value属性,可取的值是一个名为XmlAccessOrder的枚举类型的两个值,XmlAccessOrder.ALPHABETICAL 和 XmlAccessOrder.UNDEFINED。默认为XmlAccessOrder.UNDEFINED,代表按照类中字段的顺序生成元素的顺序

[email protected]

作用和用法:字段和方法级别注解。围绕被映射的xml元素生成包装元素。主要用在集合对象映射后生成包装映射结果的xml元素

属性:该注解有name、nillable、namespace、required四个属性,用法同上

修改上面的例子,添加一个Key类,在Person类中添加一个Key类的Set集合

生成的xml:

JAXB

但同一元素应该需要被“包装”一下才显得有层次感,所以可以使用@XmlElementWrapper来实现:

@XmlElementWrapper(name = "keys")
@XmlElement
public void setKey(Set<Key> key) {
    this.key = key;
}

生成的xml: 

JAXB

[email protected]

作用和用法:包、类、字段,方法、参数级别的注解。解决java日期(Date),数字(Number)格式化问题。

属性:常用的就是value属性,其他省略...

[email protected]

作用和用法:字段和方法级别的注解。该注解的作用:定义xml元素文本值的类型。例如在一个类的String类型字段上使用该注解,则生成的元素文本值类型就是xsd:string,也就是定义一个xsd中的simpleType

属性:无

[email protected]

作用和用法:类级别的注解。主要使用的是它的propOrder属性,用来定义xsd中的simpleType或complexType,从生成的xml中来看,它的作用就是:指定生成元素的顺序(标注xml生成顺序)

定义java类时,使用@XmlType(propOrder = { "id", "name", "age","book"})指定输出顺序。例子:

 @XmlRootElement  
@XmlType(propOrder = { "id", "name", "age","book"})  
public class Customer {  
    String name;   int age;   int id;   Set<Book> book;  
    @XmlElement(name="name")  
    public String getName() {  return name;  }  
    public void setName(String name) {   this.name = name;   }  
    @XmlElement(name="age")  
    public int getAge() {  
        return age;  
    }  
    public void setAge(int age) {   this.age = age;   }  
    @XmlElement(name="id")  
    public int getId() {  
        return id;  
    }  
    public void setId(int id) {    this.id = id;    }        
    @Override  
    public String toString() {  
        return "Customer [id=" + id + ",name=" + name + ",age=" + age + ",book=" + book + "]";  
    }  
    @XmlElementWrapper(name="books")  
    @XmlElement(name="book")  
    public Set<Book> getBook() {  
        return book;  
    }    
    public void setBook(Set<Book> book) {   this.book = book;   }        
}  

输出的xml:

 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>  
<customer>  
    <id>100</id>  
    <name>suo</name>  
    <age>29</age>  
    <books>  
        <book>  
            <id>1</id>  
            <name>哈里波特</name>  
            <price>100.0</price>  
        </book>  
        <book>  
            <id>2</id>  
            <name>苹果</name>  
            <price>50.0</price>  
        </book>  
    </books>  
</customer>