Elim的博客

用来记录一些原创性的总结


Elim

JAXB系列之XmlAccessorType

XmlAccessorType也是JAXB中比较常用的一个注解,可以标注在Classpackage上,标注在package上时需要标注在对应的package说明文件的package上。XmlAccessorType的作用是指定Java对象和XML相互转换时Java对象属性访问方式,它的可选值是由XmlAccessType类型的枚举指定。一共支持四种类型。

示例

以下的示例中都将使用如下这样一段相同的测试代码,所不同的只是对应的实体类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 + "]";
		}
		
	}

FIELD

示例代码:


	@XmlRootElement
	@XmlAccessorType(XmlAccessType.FIELD)
	public static class Person {
	
		//属性和方法请参考上面的定义
		
	}

在上面的示例代码中我们指定了XmlAccessorTypeXmlAccessType.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]

PROPERTY

示例代码:


	@XmlRootElement
	@XmlAccessorType(XmlAccessType.PROPERTY)
	public static class Person {
	
		//属性和方法请参考上面的定义
		
	}

在上面的示例代码中我们指定了XmlAccessorTypeXmlAccessType.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>

PUBLIC_MEMBER

示例代码:


	@XmlRootElement
	@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
	public static class Person {
	
		//属性和方法请参考上面的定义
		
	}

在上面的示例代码中我们指定了XmlAccessorTypeXmlAccessType.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>

NONE

示例代码:


	@XmlRootElement
	@XmlAccessorType(XmlAccessType.NONE)
	public static class Person {
	
		//属性和方法请参考上面的定义
		
	}

在上面的示例代码中我们指定了XmlAccessorTypeXmlAccessType.NONE。这种情况下不会自动将属性和get方法与XML进行绑定。除非在对应的属性或get方法上使用了类似于XmlElement之类的注解进行标注。满足这样条件的只有getAge2()方法,因为我们在该方法上使用了XmlElement标注,所以对应的转换后的XML结果如下所示。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<person>
    <age2>37</age2>
</person>

XmlAccessorType定义在包上示例

在上面介绍的示例都是将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;

如果packageClass上同时拥有XmlAccessorType定义时将以Class上的定义为准。

(本文由Elim写于2017年6月28日)