用来记录一些原创性的总结
XmlAccessorType
也是JAXB中比较常用的一个注解,可以标注在Class
和package
上,标注在package
上时需要标注在对应的package
说明文件的package
上。XmlAccessorType
的作用是指定Java
对象和XML
相互转换时Java
对象属性访问方式,它的可选值是由XmlAccessType
类型的枚举指定。一共支持四种类型。
static
、非transient
和非XmlTransient
标注的属性与XML
进行绑定,哪怕对应的属性是私有的。对应的get
方法只有在使用了XmlElement
等相关注解的情况下才会与XML
绑定。get/set
配对的方法与XML
进行绑定。使用XmlTransient
注解标注的get
方法不会自动与XML
进行绑定,而使用类似于XmlElement
这样的注解标注的get
方法即使没有对应的set
方法也会与XML
进行绑定。XmlTransient
标注的public
类型的get/set
方法对或没有使用transient
修饰且没有使用XmlTransient
注解标注的public
类型的属性将自动与XML
进行绑定;其它属性或get
方法如果使用了类似于XmlElement
之类的注解进行标注也会自动与XML
进行绑定。get
方法与XML
进行绑定。除非在对应的属性或get
方法上使用了类似于XmlElement
之类的注解进行标注。以下的示例中都将使用如下这样一段相同的测试代码,所不同的只是对应的实体类Person
的配置。
@Test
public void test() throws Exception {
Person person = new Person();
person.setId(1);
person.setName("张三");
person.setBirthDate(new SimpleDateFormat("yyyy").parse("1980"));
person.sex = 1;
StringWriter writer = new StringWriter();
JAXB.marshal(person, writer);
String xml = writer.toString();
String xml2 = "<person><id>2</id><name>李四</name><birthDate>1980-01-01T00:00:00+08:00</birthDate><flag>true</flag><sex>0</sex></person>";
person = JAXB.unmarshal(new StringReader(xml2), Person.class);
System.out.println(xml);
System.out.println(person);
}
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public static class Person {
private Integer id;
private String name;
private Date birthDate;
private Boolean flag = false;
private static Integer staticInt = 1;
private transient Integer transientInt = 1;
@XmlTransient
private Integer transientInt2 = 2;
public Integer sex;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBirthDate() {
return birthDate;
}
public void setBirthDate(Date birthDate) {
this.birthDate = birthDate;
}
public Integer getAge() {
if (birthDate == null) {
return null;
}
int currentYear = Calendar.getInstance().get(Calendar.YEAR);
Calendar birthCalendar = Calendar.getInstance();
birthCalendar.setTime(birthDate);
int birthYear = birthCalendar.get(Calendar.YEAR);
return currentYear - birthYear;
}
@XmlElement
public Integer getAge2() {
if (birthDate == null) {
return null;
}
int currentYear = Calendar.getInstance().get(Calendar.YEAR);
Calendar birthCalendar = Calendar.getInstance();
birthCalendar.setTime(birthDate);
int birthYear = birthCalendar.get(Calendar.YEAR);
return currentYear - birthYear;
}
@Override
public String toString() {
return "Person [id=" + id + ", name=" + name + ", birthDate=" + birthDate + ", flag=" + flag + ", sex="
+ sex + "]";
}
}
示例代码:
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public static class Person {
//属性和方法请参考上面的定义
}
在上面的示例代码中我们指定了XmlAccessorType
为XmlAccessType.FIELD
,所以在转换为XML
时应该转换我们所有的非static
、非transient
和非XmlTransient
标注的属性,转换结果如下所示,确实我们定义的static
类型的staticInt
没有被转换,transient
修饰的transientInt
没有被转换,XmlTransient
注解标注的transientInt2
也没有被转换;我们定义的private
的,没有对应get
方法的flag
属性则被转换了。另外我们拥有两个没有和属性直接相关的get
方法,其中一个加了XmlElement
注解,只有加了XmlElement
注解的get
方法在转换时被转换为XML
了。在把XML
转换为对象时也是基于属性来转换的。
输出结果:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<person>
<id>1</id>
<name>张三</name>
<birthDate>1980-01-01T00:00:00+08:00</birthDate>
<flag>false</flag>
<sex>1</sex>
<age2>37</age2>
</person>
Person [id=2, name=李四, birthDate=Tue Jan 01 00:00:00 CST 1980, flag=true, sex=0]
示例代码:
@XmlRootElement
@XmlAccessorType(XmlAccessType.PROPERTY)
public static class Person {
//属性和方法请参考上面的定义
}
在上面的示例代码中我们指定了XmlAccessorType
为XmlAccessType.PROPERTY
。这种情况将寻找get/set
这样的配对来进行XML
和对象之间的相互转换,所以我们可以看到在转换为XML
时,只转换了同时拥有get/set
方法的birthdate、id和name属性。另外使用了类似XmlElement
注解标注的get
方法也会被转换,如方法getAge2()
就被转换为了age2
元素,而没有使用任何注解标注的单独存在的getAge()
方法则没有被转换。另外如果我们的某一个属性拥有get/set
方法,但是又不希望它被自动转换为XML
时可以使用XmlTransient
注解进行标注。
转换后的XML
结果如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<person>
<age2>37</age2>
<birthDate>1980-01-01T00:00:00+08:00</birthDate>
<id>1</id>
<name>张三</name>
</person>
示例代码:
@XmlRootElement
@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
public static class Person {
//属性和方法请参考上面的定义
}
在上面的示例代码中我们指定了XmlAccessorType
为XmlAccessType.PUBLIC_MEMBER
。这种情况下没有使用XmlTransient
标注的public
类型的get/set
方法对或没有使用transient
修饰且没有使用XmlTransient
注解标注的public
类型的属性将自动与XML
进行绑定;其它属性或get
方法如果使用了类似于XmlElement
之类的注解进行标注也会自动与XML
进行绑定。这种情况下上面的示例中满足条件的就只有sex、age2、birthdate、id和name,其中birthdate、id和name是拥有public
类型的get/set
方法对;sex是使用public
修饰的属性;而age2是对应的get
方法上使用了XmlElement
注解标注。
转换后的XML
结果:
<person>
<sex>1</sex>
<age2>37</age2>
<birthDate>1980-01-01T00:00:00+08:00</birthDate>
<id>1</id>
<name>张三</name>
</person>
示例代码:
@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE)
public static class Person {
//属性和方法请参考上面的定义
}
在上面的示例代码中我们指定了XmlAccessorType
为XmlAccessType.NONE
。这种情况下不会自动将属性和get
方法与XML
进行绑定。除非在对应的属性或get
方法上使用了类似于XmlElement
之类的注解进行标注。满足这样条件的只有getAge2()
方法,因为我们在该方法上使用了XmlElement
标注,所以对应的转换后的XML
结果如下所示。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<person>
<age2>37</age2>
</person>
在上面介绍的示例都是将XmlAccessorType
标注在Class
上的,如果我们的一个包里面的所有Class
都使用相同的XmlAccessType
,则我们可以在对应的package
下创建对应的package-info.java
文件,同时在对应的package
声明上加上XmlAccessorType
注解。
@javax.xml.bind.annotation.XmlAccessorType(javax.xml.bind.annotation.XmlAccessType.FIELD)
package com.elim.learn.basic.jaxb;
如果package
和Class
上同时拥有XmlAccessorType
定义时将以Class
上的定义为准。
(本文由Elim写于2017年6月28日)