JAXB实现JavaBean与XML相互转换(详尽)

本文针对使用JAXB实现JavaBean与XML之间的相互转换,基本涵盖所有场景。

概念

JAXB是Java Architecture for XML Binding的缩写。可以将一个Java对象转变成为XML格式,反之亦然。 
    我们把对象与关系数据库之间的映射称为ORM,其实也可以把对象与XML之间的映射称为OXM(Object XML Mapping)。原来JAXB是Java EE的一部分,在JDK1.6中,SUN将其放到了Java SE中,这也是SUN的一贯做法。JDK1.6中自带的这个JAXB版本是2.0,比起1.0(JSR 31)来,JAXB2(JSR 222)用JDK5的新特性Annotation来标识要作绑定的类和属性等,这就极大简化了开发的工作量。

常见的注解说明

JAXBContext类:是应用的入口,用于管理XML/Java绑定信息。
Marshaller接口:将Java对象序列化为XML数据。
Unmarshaller接口:将XML数据反序列化为Java对象。
@XmlRootElement:将Java类或枚举类型映射到XML元素,用在Java类上,用于标注该类是xml的一个根节点。
@XmlElement:将Java类的一个属性映射到与属性同名的一个XML元素。通常与@XmlTransient搭配使用。
@XmlTransient:通常与 @XmlElement 须搭配使用的。@XmlElement用在属性上,用于指定生成xml的节点名,@XmlTransient用在对应的getter方法上,起到关联的作用。
@XmlElementWrapper :对于数组或集合(即包含多个元素的成员变量),生成一个包装该数组或集合的XML元素(称为包装器)。通常配合XmlElement一起使用,XmlElementWrapper指定数组名,XmlElement指定生成xml的节点名。
@XmlElementRef:用在类属性的getter方法上(即该属性是一个JavaBean),并且该属性是某些子类的父类,起到引用的作用。同时标注得有@XmlElementRef的类属性,其子类上需要使用@XmlRootElement标注,否则转换异常,提示找不到具体的引用实现。另外,转换时,需要将其子类的class一起传递到JAXBContext上下文中,否则也无法转换。
@XmlAccessorOrder:控制JAXB 绑定类中属性和字段的排序。

@XmlType:将Java类或枚举类型映射到XML模式类型
@XmlAccessorType(XmlAccessType.FIELD) :控制字段或属性的序列化。FIELD表示JAXB将自动绑定Java类中的每个非静态的(static)、非瞬态的(由@XmlTransient标 注)字段到XML。还有XmlAccessType.PROPERTY和XmlAccessType.NONE。
@XmlJavaTypeAdapter:使用定制的适配器(即扩展抽象类XmlAdapter并覆盖marshal()和unmarshal()方法),以序列化Java类为XML。
@XmlAttribute,将Java类的一个属性映射到与属性同名的一个XML属性。

1.工具方法

public class XmlBeanUtils {

    /**
     * Java Bean 转 Xml
     *
     * @param bean         - Java Bean
     * @param inheritClazz - Java Bean中嵌套的类,且有继承关系的Java Class
     * @return - xml
     */
    public static String beanToXml(Object bean, Class... inheritClazz) {
        try {
            JAXBContext context = initContext(bean.getClass(), inheritClazz);
            Marshaller marshaller = context.createMarshaller();
            // 格式化xml
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
            // 是否去掉xml头
            marshaller.setProperty(Marshaller.JAXB_FRAGMENT, false);
            StringWriter writer = new StringWriter();
            marshaller.marshal(bean, writer);
            return writer.toString();
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * Xml 转 Java Bean
     *
     * @param xml          - xml
     * @param beanClazz    - Java Bean Class
     * @param inheritClazz - Java Bean中嵌套的类,且有继承关系的Java Class
     * @return - bean
     */
    public static Object xmlToBean(String xml, Class beanClazz, Class... inheritClazz) {
        try {
            JAXBContext context = initContext(beanClazz, inheritClazz);
            Unmarshaller um = context.createUnmarshaller();
            StringReader sr = new StringReader(xml);
            return um.unmarshal(sr);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 初始化JAXBContext
     *
     * @param mainClazz    - 序列化或反序列化Class
     * @param inheritClazz - Java Bean中嵌套的类,且有继承关系的Java Class
     * @return - JAXBContext
     */
    private static JAXBContext initContext(Class mainClazz, Class... inheritClazz) throws JAXBException {
        JAXBContext context;
        if (inheritClazz != null) {
            Class[] clazzArr = new Class[inheritClazz.length + 1];
            clazzArr[0] = mainClazz;
            System.arraycopy(inheritClazz, 0, clazzArr, 1, clazzArr.length - 1);
            context = JAXBContext.newInstance(clazzArr);
        } else {
            context = JAXBContext.newInstance(mainClazz);
        }
        return context;
    }

}

2.应用实例

1.1.普通对象的转换

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;

/**
 * 简单JavaBean与XML转换
 */
public class SimpleTest {
    public static void main(String[] args) {
        Cat cat = new Cat("猫咪", "爱吃鱼");
        String xml = XmlBeanUtils.beanToXml(cat);
        System.out.println("bean->xml = " + xml);
        System.out.println("xml->bean = " + XmlBeanUtils.xmlToBean(xml, Cat.class));
    }

    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @Setter
    @XmlRootElement(name = "Cat")
    static class Cat {
        @XmlElement(name = "CatName")
        private String name;

        @XmlElement(name = "Hobby")
        private String hobby;

        @XmlTransient
        public String getName() {
            return name;
        }

        @XmlTransient
        public String getHobby() {
            return hobby;
        }
    }
}


JAXB实现JavaBean与XML相互转换(详尽)_第1张图片

1.2.有继承关系的对象转换

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;

/**
 * 继承关系JavaBean与XML转换
 */
public class InheritBeanTest {
    public static void main(String[] args) {
        // 具有继承关系,使用Cat 或 Animal 接收都可以。
        // Cat cat = new Cat("猫咪", "爱吃鱼");
        Animal cat = new Cat("猫咪", "爱吃鱼");
        String xml = XmlBeanUtils.beanToXml(cat);
        System.out.println("bean->xml = " + xml);
        // 此处不能使用父类Animal来接收,因为无法推断具体的实现类是哪个,必须使用具体的实现类Cat来接收
        System.out.println("xml->bean = " + XmlBeanUtils.xmlToBean(xml, Cat.class));
    }

    @Setter
    abstract static class Animal {
        // 不建议定义属性,因为从XML->Bean时,父类属性会丢失
    }

    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @Setter
    @XmlRootElement(name = "Cat")
    static class Cat extends Animal {
        @XmlElement(name = "CatName")
        private String name;

        @XmlElement(name = "Hobby")
        private String hobby;

        @XmlTransient
        public String getName() {
            return name;
        }

        @XmlTransient
        public String getHobby() {
            return hobby;
        }
    }
}

JAXB实现JavaBean与XML相互转换(详尽)_第2张图片

1.3.嵌套的类属性是普通对象的转换

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;

/**
 * 有嵌套关系的JavaBean与XML转换
 */
public class NestBeanTest {
    public static void main(String[] args) {
        Cat cat = new Cat("猫咪", "爱吃鱼");
        Person person = new Person("貂蝉", 18, cat);
        String xml = XmlBeanUtils.beanToXml(person);
        System.out.println("bean->xml = " + xml);
        System.out.println("xml->bean = " + XmlBeanUtils.xmlToBean(xml, Person.class));
    }

    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @Setter
    @XmlRootElement(name = "Person")
    static class Person {
        @XmlElement(name = "UserName")
        private String name;

        @XmlElement(name = "Age")
        private int age;

        // 嵌套的JavaBean
        @XmlElement(name = "Pet")
        private Cat cat;

        @XmlTransient
        public String getName() {
            return name;
        }

        @XmlTransient
        public int getAge() {
            return age;
        }

        @XmlTransient
        public Cat getCat() {
            return cat;
        }
    }


    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @Setter
    @XmlRootElement(name = "Cat")
    static class Cat {
        @XmlElement(name = "CatName")
        private String name;

        @XmlElement(name = "Hobby")
        private String hobby;

        @XmlTransient
        public String getName() {
            return name;
        }

        @XmlTransient
        public String getHobby() {
            return hobby;
        }
    }
}


JAXB实现JavaBean与XML相互转换(详尽)_第3张图片1.4.嵌套类属性是的集合(数组)普通对象的转换

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import java.util.ArrayList;
import java.util.List;

/**
 * 有嵌套关系的集合JavaBean与XML转换
 */
public class NestListBeanTest {
    public static void main(String[] args) {
        List cats = new ArrayList<>();
        cats.add(new Cat("大猫咪", "爱吃大鱼"));
        cats.add(new Cat("小猫咪", "爱吃小鱼"));
        Person person = new Person("貂蝉", 18, cats);
        String xml = XmlBeanUtils.beanToXml(person);
        System.out.println("bean->xml = " + xml);
        System.out.println("xml->bean = " + XmlBeanUtils.xmlToBean(xml, Person.class));
    }

    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @Setter
    @XmlRootElement(name = "Person")
    static class Person {
        @XmlElement(name = "UserName")
        private String name;

        @XmlElement(name = "Age")
        private int age;

        // 嵌套的集合JavaBean:XmlElementWrapper指定集合数组XML节点名,XmlElement指定具体的节点名
        @XmlElementWrapper(name = "PetArray")
        @XmlElement(name = "Pet")
        private List cats;

        @XmlTransient
        public String getName() {
            return name;
        }

        @XmlTransient
        public int getAge() {
            return age;
        }

        @XmlTransient
        public List getCats() {
            return cats;
        }
    }


    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @Setter
    @XmlRootElement(name = "Cat")
    static class Cat {
        @XmlElement(name = "CatName")
        private String name;

        @XmlElement(name = "Hobby")
        private String hobby;

        @XmlTransient
        public String getName() {
            return name;
        }

        @XmlTransient
        public String getHobby() {
            return hobby;
        }
    }
}


JAXB实现JavaBean与XML相互转换(详尽)_第4张图片1.5.嵌套的类属性是继承关系对象的转换

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;

/**
 * 有嵌套且有继承关系的JavaBean与XML转换
 */
public class NestInheritBeanTest {
    public static void main(String[] args) {
        // 此处使用Animal或Cat来接收都是可以的,因为已经创建了具体的Bean
        Animal cat = new Cat("猫咪", "爱吃鱼");
        Person person = new Person("貂蝉", 18, cat);
        // 转换时需要将Person中Animal类属性的实现类Cat.class传入。否则无法无法转换,因为不清楚具体的实现。
        String xml = XmlBeanUtils.beanToXml(person, Cat.class);
        System.out.println("bean->xml = " + xml);
        // 转换时需要将Person中Animal类属性的实现类Cat.class传入。否则无法无法转换,因为不清楚具体的实现。
        System.out.println("xml->bean = " + XmlBeanUtils.xmlToBean(xml, Person.class, Cat.class));
    }

    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @Setter
    @XmlRootElement(name = "Person")
    static class Person {
        @XmlElement(name = "UserName")
        private String name;

        @XmlElement(name = "Age")
        private int age;

        // 嵌套的JavaBean,且是父类,此处不能使用@XmlElement标注,否则会报错,
        // 原因是父类不知道具体的子类实现,需要在子类中使用@XmlRootElement标注具体的实现
        private Animal animal;

        @XmlTransient
        public String getName() {
            return name;
        }

        @XmlTransient
        public int getAge() {
            return age;
        }

        // 必须使用@XmlElementRef来标注父类,起到引用的作用
        @XmlElementRef
        public Animal getAnimal() {
            return animal;
        }
    }


    @Setter
    abstract static class Animal {
    }

    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @Setter
    @XmlRootElement(name = "Cat")
    static class Cat extends Animal {
        @XmlElement(name = "CatName")
        private String name;

        @XmlElement(name = "Hobby")
        private String hobby;

        @XmlTransient
        public String getName() {
            return name;
        }

        @XmlTransient
        public String getHobby() {
            return hobby;
        }
    }
}


1.6.嵌套的类属性是集合(数组)继承关系对象的转换

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

import javax.xml.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 有嵌套且有继承关系的集合JavaBean与XML转换
 */
public class NestInheritListBeanTest {
    public static void main(String[] args) {
        // 此处使用Animal来接,属于List泛型知识,此处不再赘述
        List animals = new ArrayList<>();
        animals.add(new Cat("大猫咪", "爱吃大鱼"));
        animals.add(new Cat("小猫咪", "爱吃小鱼"));
        Person person = new Person("貂蝉", 18, animals);
        // 转换时需要将Person中Animal类属性的实现类Cat.class传入。否则无法无法转换,因为不清楚具体的实现。
        String xml = XmlBeanUtils.beanToXml(person, Cat.class);
        System.out.println("bean->xml = " + xml);
        // 转换时需要将Person中Animal类属性的实现类Cat.class传入。否则无法无法转换,因为不清楚具体的实现。
        System.out.println("xml->bean = " + XmlBeanUtils.xmlToBean(xml, Person.class, Cat.class));
    }

    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @Setter
    @XmlRootElement(name = "Person")
    static class Person {
        @XmlElement(name = "UserName")
        private String name;

        @XmlElement(name = "Age")
        private int age;

        // 嵌套的JavaBean,且是父类,此处不能使用@XmlElement标注,否则会报错,
        // 原因是父类不知道具体的子类实现,需要在子类中使用@XmlRootElement标注具体的实现
        private List animals;

        @XmlTransient
        public String getName() {
            return name;
        }

        @XmlTransient
        public int getAge() {
            return age;
        }

        // 必须使用@XmlElementRef来标注父类,起到引用的作用
        // 必须使用@XmlElementWrapper指定集合数组XML节点名
        @XmlElementRef
        @XmlElementWrapper(name = "PetArray")
        public List getAnimals() {
            return animals;
        }
    }

    @Setter
    abstract static class Animal {
    }

    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @Setter
    @XmlRootElement(name = "Cat")
    static class Cat extends Animal {
        @XmlElement(name = "CatName")
        private String name;

        @XmlElement(name = "Hobby")
        private String hobby;

        @XmlTransient
        public String getName() {
            return name;
        }

        @XmlTransient
        public String getHobby() {
            return hobby;
        }
    }
}

JAXB实现JavaBean与XML相互转换(详尽)_第5张图片1.7.有继承关系且父类有属性的对象的转换

(不推荐使用,XML->Bean转换时父类属性会丢失

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;

/**
 * 有嵌套且有继承关系的JavaBean与XML转换
 * 且父类中定义了属性,XML->Bean,父类属性会丢失(除非必要,不要再父类中定义属性)
 */
public class NoSupportNestInheritBeanTest {
    public static void main(String[] args) {
        // 此处使用Animal或Cat来接收都是可以的,因为已经创建了具体的Bean
        Cat cat = new Cat("猫咪", "爱吃鱼");
        cat.setCountry("中国");
        Person person = new Person("貂蝉", 18, cat);
        // 转换时需要将Person中Animal类属性的实现类Cat.class传入。否则无法无法转换,因为不清楚具体的实现。
        String xml = XmlBeanUtils.beanToXml(person, Cat.class);
        System.out.println("bean->xml = " + xml);
        // 转换时需要将Person中Animal类属性的实现类Cat.class传入。否则无法无法转换,因为不清楚具体的实现。
        System.out.println("xml->bean = " + XmlBeanUtils.xmlToBean(xml, Person.class, Cat.class));
    }

    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @Setter
    @XmlRootElement(name = "Person")
    static class Person {
        @XmlElement(name = "UserName")
        private String name;

        @XmlElement(name = "Age")
        private int age;

        // 嵌套的JavaBean,且是父类,此处不能使用@XmlElement标注,否则会报错,
        // 原因是父类不知道具体的子类实现,需要在子类中使用@XmlRootElement标注具体的实现
        private Animal animal;

        @XmlTransient
        public String getName() {
            return name;
        }

        @XmlTransient
        public int getAge() {
            return age;
        }

        // 必须使用@XmlElementRef来标注父类,起到引用的作用
        @XmlElementRef
        public Animal getAnimal() {
            return animal;
        }
    }


    @Setter
    abstract static class Animal {
        @XmlElement(name = "Country")
        private String country;

        @XmlTransient
        public String getCountry() {
            return country;
        }
    }

    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @Setter
    @XmlRootElement(name = "Cat")
    static class Cat extends Animal {
        @XmlElement(name = "CatName")
        private String name;

        @XmlElement(name = "Hobby")
        private String hobby;

        @XmlTransient
        public String getName() {
            return name;
        }

        @XmlTransient
        public String getHobby() {
            return hobby;
        }
    }
}

你可能感兴趣的:(Java专栏,xml,java)