JAXB中XmlJavaTypeAdapter的使用方法

JAXB中提供了XmlJavaTypeAdapter类,用于将JAXB不知道如何进行映射的类转换到可以映射的类。

XmlJavaTypeAdapter使用XmlAdapter接口来转换。XmlAdapter接口定义如下:

public abstract class XmlAdapter<ValueType,BoundType> {

    /**
     * Do-nothing constructor for the derived classes.
     */
    protected XmlAdapter() {}

    /**
     * Convert a value type to a bound type.
     *
     * @param v
     *      The value to be converted. Can be null.
     * @throws Exception
     *      if there's an error during the conversion. The caller is responsible for
     *      reporting the error to the user through {@link javax.xml.bind.ValidationEventHandler}.
     */
    public abstract BoundType unmarshal(ValueType v) throws Exception;

    /**
     * Convert a bound type to a value type.
     *
     * @param v
     *      The value to be convereted. Can be null.
     * @throws Exception
     *      if there's an error during the conversion. The caller is responsible for
     *      reporting the error to the user through {@link javax.xml.bind.ValidationEventHandler}.
     */
    public abstract ValueType marshal(BoundType v) throws Exception;
}


可以看到XmlAdapter提供两个方法:marshal和unmarshal。注意marshal是把ValueType转成BoundType,unmarshal是反之。接下来就可以写样例代码了,假设有Person类如下:

    public static class Person {
        private String name;
        private String gender;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getGender() {
            return gender;
        }

        public void setGender(String gender) {
            this.gender = gender;
        }
    }


我们有House类使用它:

    public static class House {

        private Person host;

        public Person getHost() {
            return host;
        }

        public void setHost(Person host) {
            this.host = host;
        }
    }


假设我们的xml当中使用字符来保存Person,那么就需要使用Adapter将字串转成Person类,因此可以标记House类如下:

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

        @XmlJavaTypeAdapter(PersonAdapter.class)
        private Person host;

        public Person getHost() {
            return host;
        }

        public void setHost(Person host) {
            this.host = host;
        }
    }


注意host使用了Adapter:

        
        @XmlJavaTypeAdapter(PersonAdapter.class)
        private Person host;



PersonAdapter的代码如下:

    public static class PersonAdapter extends XmlAdapter<String, Person> {
        @Override
        public Person unmarshal(String str) throws Exception {
            Person p = new Person();
            p.setName(str.split(":")[0]);
            p.setGender(str.split(":")[1]);
            return p;
        }

        @Override
        public String marshal(Person person) throws Exception {
            return (person.getName() + ":" + person.getGender());
        }
    }


我们定义输入输出的Person的字串格式为:"name:gender",因此在marshal与unmarshal里面有相关处理。

最后撰写测试代码:

    public static void main(String[] args) throws Exception {
        JAXBContext ctx = JAXBContext.newInstance(House.class);

        House house = new House();
        Person host = new Person();
        host.setName("Weinan");
        host.setGender("Male");
        house.setHost(host);

        ctx.createMarshaller().marshal(house, System.out);
    }


输出如下:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><house><host>Weinan:Male</host></house>


最后想说说这里:

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


其中XmlAccessorType用来标记House类中什么元素需要被marshal和unmarshal,我们指定为XmlAccessType.FIELD,默认是XmlAccessType.PUBLIC_MEMBER。因为我们的House类中同时有getter和field,不指定为FIELD执行时会产生以下错误:

Exception in thread "main" com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
Class has two properties of the same name "host"
	this problem is related to the following location:
		at public xml.PlayWithXmlTypeAdapter$Person xml.PlayWithXmlTypeAdapter$House.getHost()
...
Process finished with exit code 1

你可能感兴趣的:(xml)