JAXB 中的@XmlElementWrapper注解生成问题

JAXB 中的@XmlElementWrapper注解生成问题

本文同步发表在 http://www.simonme.org/?p=220

1. 面临的问题场景

<?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默认生成的代码,会需要这样去使用

 

    @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注解来做这个事情。

 

2. 用@XmlElementWrapper注解使代码更精致

将Root类的代码改造成这样:

@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;
    }

}

这样测试代码只需要写成

 @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生成,如下:

<?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.xxx.xxx.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)。下面介绍如何使用。

首先这个插件需要匹配JAXB 2.2版本,目前还不兼容于JAXB2.0版本,如果使用2.0版本,会出现NoSuchMethod之类的异常。去jaxb官网找到类似jaxb-ri-2.2.6 的zip包

引用。

编写ant脚本如下:

<?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.xxx.xxx.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注解。

原文地址:https://www.cnblogs.com/simoncook/p/2941357.html