用来记录一些原创性的总结
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日)