Elim的博客

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


Elim

JAXB系列之XMLElementWrapper

先来看一下假设我们有如下这样结构的两个Class定义。


	@XmlRootElement
	@XmlAccessorType(XmlAccessType.FIELD)
	public static class User {

		private Integer id;
		private String name;
		@XmlElement(name="post")
		private List<Post> posts;
		//...省略get/set方法
	}
	
	@XmlAccessorType(XmlAccessType.FIELD)
	public static class Post {
		private Integer id;
		private String name;
		//...省略get/set方法
	}

如果我们需要通过JAXB把它转换为对应的XML表示,那结果会是怎样呢?我们来看下面的测试代码及其输出结果。


	@Test
	public void test() {

		User user = new User();
		user.setId(1);
		user.setName("张三");
		List<Post> posts = new ArrayList<>();
		for (int i=0; i<3; i++) {
			Post post = new Post();
			post.setId(i+1);
			post.setName(String.valueOf((char)('A'+i)));
			posts.add(post);
		}
		user.setPosts(posts);
		JAXB.marshal(user, System.out);
		
	}

上面的测试代码的输出结果如下:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<user>
    <id>1</id>
    <name>张三</name>
    <post>
        <id>1</id>
        <name>A</name>
    </post>
    <post>
        <id>2</id>
        <name>B</name>
    </post>
    <post>
        <id>3</id>
        <name>C</name>
    </post>
</user>

从上面的输出结果我们可以看到JAXB在转换对象为XML时默认会把对象中的List类型的属性(其实不只是java.util.List,更确切的说是java.util.Collection)分别把其中包含的元素转换为对应的XML,且对应的根节点元素名称由List类型的属性决定,在上面的示例中我们通过在posts属性上加上@XmlElement(name="post")指定了其节点名称为post。这种输出结果是ok的,但是有时候我们可能希望post节点不直接出现在user节点下,而是希望可以多包一层posts,形成user>posts>post这样的结构。这其实很简单,我们只需要在对应的集合属性上加上XmlElementWrapper注解,这样JAXB就会自动为我们多包一层。我们也可以通过XmlElementWrappername属性指定需要多包一层的元素的名称,不指定时默认会以对应的属性名为名。

XmlElementWrapper不一定是加在属性上,这取决于你的XmlAccessorType定义,像笔者的示例里面XmlAccessorType指定的是FIELD,所以就加在属性上。

使用XmlElementWrapper注解标注后的代码如下:


	@XmlRootElement
	@XmlAccessorType(XmlAccessType.FIELD)
	public static class User {

		private Integer id;
		private String name;
		@XmlElementWrapper(name="posts")
		@XmlElement(name="post")
		private List<Post> posts;
		//... 省略get/set方法
	}

同样运行原来的测试代码,这个时候生成的XML就是如下这样:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<user>
    <id>1</id>
    <name>张三</name>
    <posts>
        <post>
            <id>1</id>
            <name>A</name>
        </post>
        <post>
            <id>2</id>
            <name>B</name>
        </post>
        <post>
            <id>3</id>
            <name>C</name>
        </post>
    </posts>
</user>

需要注意的是XmlElementWrapper只能用于标注集合类型。

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