JAXB 中的@XmlElementWrapper注解生成问题
1. 面临的问题场景
1
2
3
4
5
6
7
|
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<root
xmlns
=
"http://www.example.org/JaxbEleWrapperSchema"
>
<students>
<student
sno
=
"001"
name
=
"Simon"
/>
<student
sno
=
"002"
name
=
"Eva"
/>
</students>
</root>
|
当我们需要用JAXB处理(生成或读取)这样的xml文件时,根据xjc默认生成的代码,会需要这样去使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
@Test
public
void
test
(
)
{
Root
root
=
new
Root
(
)
;
Student
stu
=
new
Student
(
)
;
stu
.
setName
(
"Simon"
)
;
stu
.
setSno
(
"001"
)
;
Student
stu1
=
new
Student
(
)
;
stu1
.
setName
(
"Eva"
)
;
stu1
.
setSno
(
"002"
)
;
Students
students
=
new
Students
(
)
;
students
.
getStudent
(
)
.
add
(
stu
)
;
students
.
getStudent
(
)
.
add
(
stu1
)
;
root
.
setStudents
(
students
)
;
String
testFilename
=
"d:/test.xml"
;
JAXBUtils
.
object2xmlFile
(
root
,
testFilename
)
;
}
|
这样代码看起来貌似不太理想,主要是针对Students 对象处理的地方,貌似有点多余,其实本意上就是想用<students>这个标签把<student>元素包起来,无其他用处。怎样解决这个貌似多余代码的问题呢? JAXB提供了@XmlElementWrapper注解来做这个事情。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
@XmlRootElement
@XmlAccessorType
(
XmlAccessType
.
FIELD
)
@XmlType
(
name
=
"Root"
)
public
class
Root
{
@XmlElementWrapper
(
name
=
"students"
)
@XmlElement
(
required
=
true
)
protected
List
<Student>
student
;
public
List
<Student>
getStudent
(
)
{
if
(
student
==
null
)
{
student
=
new
ArrayList
<Student>
(
)
;
}
return
student
;
}
public
void
setStudent
(
List
<Student>
student
)
{
this
.
student
=
student
;
}
}
|
2. 用@XmlElementWrapper注解使代码更精致
将Root类的代码改造成这样:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
@Test
public
void
test
(
)
{
Root
root
=
new
Root
(
)
;
Student
stu
=
new
Student
(
)
;
stu
.
setName
(
"Simon"
)
;
stu
.
setSno
(
"001"
)
;
Student
stu1
=
new
Student
(
)
;
stu1
.
setName
(
"Eva"
)
;
stu1
.
setSno
(
"002"
)
;
root
.
getStudent
(
)
.
add
(
stu
)
;
root
.
getStudent
(
)
.
add
(
stu1
)
;
String
testFilename
=
"d:/test.xml"
;
JAXBUtils
.
object2xmlFile
(
root
,
testFilename
)
;
}
|
这样测试代码只需要写成
这样更精致,但是又一个问题来了,一般我们用JAXB,代码都是用xjc命令行或者xjc的ant task生成,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<project
name
=
"test"
default
=
"run"
basedir
=
"."
>
<taskdef
name
=
"xjc"
classname
=
"com.sun.tools.xjc.XJCTask"
>
<classpath>
<fileset
dir
=
"D:/004.work/02.tools/jaxb-ri-2.2.6/jaxb-ri-2.2.6/lib"
includes
=
"*.jar"
/>
</classpath>
</taskdef>
<target
name
=
"run"
>
<xjc
destdir
=
"D:/004.work/03.workspace/02.plugin_dev_demo/JaxbElementWarp/src"
package
=
"com.xxxx.xixx.demo.xsd.test"
>
<schema
dir
=
"D:/004.work/03.workspace/02.plugin_dev_demo/JaxbElementWarp/src"
includes
=
"JaxbEleWrapper.xsd"
/>
</xjc>
</target>
</project>
|
但是这个我们手工干预的貌似很麻烦,如何让他自动生成@XmlElementWrapper这个注解,并对代码做相应调整。
3. 如何用xjc生成@XmlElementWrapper注解
需要使用github上的这个jaxb-xew-plugin.jarxjc插件(https://github.com/wumpz/jaxb-xew-plugin)。You can download the jar file from here.下面介绍如何使用。
首先这个插件需要匹配JAXB 2.2版本,目前还不兼容于JAXB2.0版本,如果使用2.0版本,会出现NoSuchMethod之类的异常。去jaxb官网找到类似jaxb-ri-2.2.6 的zip包
引用。
编写ant脚本如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<project
name
=
"test"
default
=
"run"
basedir
=
"."
>
<taskdef
name
=
"xjc"
classname
=
"com.sun.tools.xjc.XJCTask"
>
<classpath>
<fileset
dir
=
"D:/004.work/02.tools/jaxb-ri-2.2.6/jaxb-ri-2.2.6/lib"
includes
=
"*.jar"
/>
<fileset
dir
=
"D:/004.work/02.tools"
includes
=
"jaxb-xew-plugin.jar"
/>
</classpath>
</taskdef>
<target
name
=
"run"
>
<xjc
destdir
=
"D:/004.work/03.workspace/02.plugin_dev_demo/JaxbElementWarp/src"
package
=
"com.xxxx.xxxx.demo.xsd.test"
>
<arg
value
=
"-Xxew"
/>
<!-- <arg value="-Xxew:instantiate lazy" /> -->
<schema
dir
=
"D:/004.work/03.workspace/02.plugin_dev_demo/JaxbElementWarp/src"
includes
=
"JaxbEleWrapper.xsd"
/>
</xjc>
</target>
</project>
|
具体用法可以参见https://github.com/wumpz/jaxb-xew-plugin文档。
这个插件目前能做到我们想要的效果,但是多余的Students类仍然会生成,但是无碍功能,可以手动删除,并在ObjectFactory类中去掉对其的引用。
4. jaxb-xew-plugin一点思考
目前的玩法是先在xsd中定义上studetns这样的元素(把下面的student子元素包起来的元素),然后再用jaxb-xew-plugin插件生成。
而不是:我们不在xsd文件中定义students元素,仅仅凭student元素是0到多个或者1到多个来生成@XmlElementWrapper注解。