Java对象和XML的相互转换化


转载链接:Java对象和XML的相互转换化

重点:Jaxb是JavaEE的规范.全称Java Architecture for XML Binding. 可以根据XML Schema产生Java类的技术.JAXB也提供了将XML实例文档反向生成Java对象树的方法,并能将Java对象树的内容重新写到XML实例文档. JAXB 2.0是JDK 1.6的组成部分。JAXB 2.2.3是JDK 1.7的组成部分,在实际使用不需要引入新的jar.

1. 常用注解说明
常用的annotation有:
@XmlType
@XmlElement
@XmlRootElement
@XmlAttribute
@XmlAccessorType
@XmlAccessorOrder
@XmlTransient
@XmlJavaTypeAdapter
@Temporal(TemporalType.XXXX) -->JPA中的时间处理注解,非JAXB
@XmlElementWrapper

1.@XmlType
  @XmlType用在class类的注解,常与@XmlRootElement,@XmlAccessorType一起使用。它有三个属性:name、propOrder、namespace,经常使用的只有前两个属性。如:
同时使用了@XmlType(propOrder={})和@XmlAccessorOrder(XmlAccessOrder.ALPHABETICAL)的时候,生成的xml只按照propOrder定义的顺序生成元素
@XmlType(name = "basicStruct", propOrder = {
"intValue",
"stringArray",
"stringValue"
)
在使用@XmlType的propOrder 属性时,必须列出JavaBean对象中的所有属性,否则会报错。

2.@XmlRootElement
  @XmlRootElement用于类级别的注解,对应xml的跟元素,常与 @XmlType 和 @XmlAccessorType一起使用。如:
  @XmlType
  @XmlAccessorType(XmlAccessType.FIELD)
  @XmlRootElement
  public class Address {}

3.@XmlElement
  @XmlElement将java对象的属性映射为xml的节点,在使用@XmlElement时,可通过name属性改变java对象属性在xml中显示的名称。如:
  @XmlElement(name="Address")  
  private String yourAddress;

4.@XmlAttribute
  @XmlAttribute用于把java对象的属性映射为xml的属性,并可通过name属性为生成的xml属性指定别名。如:
  @XmlAttribute(name="Country")
  private String state;

5.@XmlAccessorType
  @XmlAccessorType用于指定由java对象生成xml文件时对java对象属性的访问方式。常与@XmlRootElement、@XmlType一起使用。它的属性值是XmlAccessType的4个枚举值,分别为:

XmlAccessType.FIELD:java对象中的所有成员变量
XmlAccessType.PROPERTY:java对象中所有通过getter/setter方式访问的成员变量
XmlAccessType.PUBLIC_MEMBER:java对象中所有的public访问权限的成员变量和通过getter/setter方式访问的成员变量
XmlAccessType.NONE:java对象的所有属性都不映射为xml的元素
注意:@XmlAccessorType的默认访问级别是XmlAccessType.PUBLIC_MEMBER,因此,如果java对象中的private成员变量设置了public权限的getter/setter方法,就不要在private变量上使用@XmlElement和@XmlAttribute注解,否则在由java对象生成xml时会报同一个属性在java类里存在两次的错误。同理,如果@XmlAccessorType的访问权限为XmlAccessType.NONE,如果在java的成员变量上使用了@XmlElement或@XmlAttribute注解,这些成员变量依然可以映射到xml文件。

注意:虽然@XmlAccessorType为XmlAccessType.NONE,但是在java类的私有属性上加了@XmlAttribute和@XmlElement注解后,这些私有成员会映射生成xml的元素

6.@XmlAccessorOrder
  @XmlAccessorOrder用于对java对象生成的xml元素进行排序。它有两个属性值:
  AccessorOrder.ALPHABETICAL:对生成的xml元素按字母书序排序
  XmlAccessOrder.UNDEFINED:不排序

7.@XmlTransient
  @XmlTransient用于标示在由java对象映射xml时,忽略此属性。即,在生成的xml文件中不出现此元素。

8.@XmlJavaTypeAdapter
  @XmlJavaTypeAdapter常用在转换比较复杂的对象时,如map类型或者格式化日期等。使用此注解时,需要自己写一个adapter类继承XmlAdapter抽象类,并实现里面的方法。
  @XmlJavaTypeAdapter(value=xxx.class),value为自己定义的adapter类
  XmlAdapter 抽象接口如下:

public abstract class XmlAdapter { // Do-nothing constructor for the derived classes.
    protected XmlAdapter() {}
    // Convert a value type to a bound type.
    public abstract BoundType unmarshal(ValueType v);
    // Convert a bound type to a value type.
    public abstract ValueType marshal(BoundType v);
}

下面举一个简单的例子:

1.School类 一些基本的属性,包含Student集合

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

@XmlRootElement(name = "list")
public class School {
    private String name;
    private String address;
    private String level;
    private long popular;
    private List students = new ArrayList();

    @XmlElement(name = "name")
    public String getName() {
        return name;
    }

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

    @XmlElement(name = "address")
    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @XmlElement(name = "level")
    public String getLevel() {
        return level;
    }

    public void setLevel(String level) {
        this.level = level;
    }

    @XmlElement(name = "popular")
    public long getPopular() {
        return popular;
    }

    public void setPopular(long popular) {
        this.popular = popular;
    }

    @XmlElement(name = "Student")
    public List getStudents() {
        return students;
    }

    public void setStudents(List students) {
        this.students = students;
    }
}

2.Student类,包含爱好集合和一些基本的属性

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import java.util.List;

public class Student {
    String name; //姓名
    String sex; //性别
    int number; //学号
    String className; //班级
    List hobby; //爱好

    public Student() {
    }

    public Student(String name, String sex, int number,
                   String className, List hobby) {
        this.name = name;
        this.sex = sex;
        this.number = number;
        this.className = className;
        this.hobby = hobby;
    }

    @XmlAttribute(name = "name")
    public String getName() {
        return name;
    }

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

    @XmlAttribute(name = "sex")
    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    @XmlAttribute(name = "number")
    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    @XmlElement(name = "className")
    public String getClassName() {
        return className;
    }

    public void setClassName(String className) {
        this.className = className;
    }

    @XmlElementWrapper(name = "hobbys")
    @XmlElement(name = "hobby")
    public List getHobby() {
        return hobby;
    }

    public void setHobby(List hobby) {
        this.hobby = hobby;
    }

}


3.工具类,提供xml到javaBean的相互转换 由 valvin大神提供,很好用(自己看其中的方法,说不定有你需要的)

import java.io.StringReader;
import java.io.StringWriter;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.namespace.QName;

import com.gs.mountain.common.utils.StringUtils;
import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.util.Assert;

import com.gs.mountain.common.utils.Exceptions;
import com.gs.mountain.common.utils.Reflections;

/**
 * 使用Jaxb2.0实现XML<->Java Object的Mapper.
 * 

* 在创建时需要设定所有需要序列化的Root对象的Class. * 特别支持Root对象是Collection的情形. * * @author calvin * @version 2013-01-15 */ @SuppressWarnings("rawtypes") public class JaxbMapper { private static ConcurrentMap jaxbContexts = new ConcurrentHashMap(); /** * Java Object->Xml without encoding. */ public static String toXml(Object root) { Class clazz = Reflections.getUserClass(root); return toXml(root, clazz, null); } /** * Java Object->Xml with encoding. */ public static String toXml(Object root, String encoding) { Class clazz = Reflections.getUserClass(root); return toXml(root, clazz, encoding); } /** * Java Object->Xml with encoding. */ public static String toXml(Object root, Class clazz, String encoding) { try { StringWriter writer = new StringWriter(); createMarshaller(clazz, encoding).marshal(root, writer); return writer.toString(); } catch (JAXBException e) { throw Exceptions.unchecked(e); } } /** * Java Collection->Xml without encoding, 特别支持Root Element是Collection的情形. */ public static String toXml(Collection<?> root, String rootName, Class clazz) { return toXml(root, rootName, clazz, null); } /** * Java Collection->Xml with encoding, 特别支持Root Element是Collection的情形. */ public static String toXml(Collection<?> root, String rootName, Class clazz, String encoding) { try { CollectionWrapper wrapper = new CollectionWrapper(); wrapper.collection = root; JAXBElement wrapperElement = new JAXBElement(new QName(rootName), CollectionWrapper.class, wrapper); StringWriter writer = new StringWriter(); createMarshaller(clazz, encoding).marshal(wrapperElement, writer); return writer.toString(); } catch (JAXBException e) { throw Exceptions.unchecked(e); } } /** * Xml->Java Object. */ @SuppressWarnings("unchecked") public static T fromXml(String xml, Class clazz) { try { StringReader reader = new StringReader(xml); return (T) createUnmarshaller(clazz).unmarshal(reader); } catch (JAXBException e) { throw Exceptions.unchecked(e); } } /** * 创建Marshaller并设定encoding(可为null). * 线程不安全,需要每次创建或pooling。 */ public static Marshaller createMarshaller(Class clazz, String encoding) { try { JAXBContext jaxbContext = getJaxbContext(clazz); Marshaller marshaller = jaxbContext.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); if (StringUtils.isNotBlank(encoding)) { marshaller.setProperty(Marshaller.JAXB_ENCODING, encoding); } return marshaller; } catch (JAXBException e) { throw Exceptions.unchecked(e); } } /** * 创建UnMarshaller. * 线程不安全,需要每次创建或pooling。 */ public static Unmarshaller createUnmarshaller(Class clazz) { try { JAXBContext jaxbContext = getJaxbContext(clazz); return jaxbContext.createUnmarshaller(); } catch (JAXBException e) { throw Exceptions.unchecked(e); } } protected static JAXBContext getJaxbContext(Class clazz) { Assert.notNull(clazz, "'clazz' must not be null"); JAXBContext jaxbContext = jaxbContexts.get(clazz); if (jaxbContext == null) { try { jaxbContext = JAXBContext.newInstance(clazz, CollectionWrapper.class); jaxbContexts.putIfAbsent(clazz, jaxbContext); } catch (JAXBException ex) { throw new HttpMessageConversionException("Could not instantiate JAXBContext for class [" + clazz + "]: " + ex.getMessage(), ex); } } return jaxbContext; } /** * 封装Root Element 是 Collection的情况. */ public static class CollectionWrapper { @XmlAnyElement protected Collection<?> collection; } }

4.下面是测试的代码,结果很棒,so easy!

import com.gs.mountain.common.mapper.JaxbMapper;

import javax.xml.bind.JAXBException;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class BeanToXml {

    public static void main(String[] args) throws JAXBException, IOException {
        List hobby = new ArrayList();
        hobby.add("篮球");
        hobby.add("音乐");
        hobby.add("乒乓球");

        List studentList = new ArrayList();

        Student st = new Student("张三", "男", 10001, "尖子班", hobby);
        studentList.add(st);
        Student st1 = new Student("李四", "男", 10002, "普通班", hobby);
        studentList.add(st1);
        Student st2 = new Student("莉莉", "女", 10003, "普通班", hobby);
        studentList.add(st2);

        School school = new School();
        School school1;
        School school2;
        school.setAddress("成都市武侯区天府五街");
        school.setLevel("高级中学");
        school.setName("华阳中学");
        school.setPopular(5000L);
        school.setStudents(studentList);
        school1 = school;
        school2 = school;
        List listSchool = new ArrayList();
        listSchool.add(school);
        listSchool.add(school1);
        listSchool.add(school2);
        String str = JaxbMapper.toXml(listSchool, "schoolList", School.class);

        //写入到xml文件中
        String xmlPath = "D:/testConfig.xml";
        BufferedWriter bfw = new BufferedWriter(new FileWriter(new File(xmlPath)));
        bfw.write(str);
        bfw.close();
    }
}

下面是由 listSchool 转化成的 xml 文件,内容如下:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

    
        
成都市武侯区天府五街
高级中学 华阳中学 5000 尖子班 篮球 音乐 乒乓球 普通班 篮球 音乐 乒乓球 普通班 篮球 音乐 乒乓球
成都市武侯区天府五街
高级中学 华阳中学 5000 尖子班 篮球 音乐 乒乓球 普通班 篮球 音乐 乒乓球 普通班 篮球 音乐 乒乓球
成都市武侯区天府五街
高级中学 华阳中学 5000 尖子班 篮球 音乐 乒乓球 普通班 篮球 音乐 乒乓球 普通班 篮球 音乐 乒乓球

博主讲解的很详细,知识点罗列的很清晰,可以尝试着写写样例用到工作当中!