Java对象和XML的相互转换化

来源:互联网 发布:linux 获取网卡流量 编辑:程序博客网 时间:2024/06/05 15:50
写在前面: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<ValueType,BoundType> {    // 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集合

package com.gs.mountain.test.xml;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<Student> students=new ArrayList<Student>();@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<Student> getStudents() {return students;}public void setStudents(List<Student> students) {this.students = students;}}

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

package com.gs.mountain.test.xml;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<String> hobby;    //爱好    public Student(){    }    public Student(String name,String sex,int number,                   String className,List<String> 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<String> getHobby() {        return hobby;    }    public void setHobby(List<String> hobby) {        this.hobby = hobby;    }}
3.工具类,提供xml到javaBean的相互转换 由 valvin大神提供,很好用(自己看其中的方法,说不定有你需要的)
/** * Copyright (c) 2005-2012 springside.org.cn */package com.gs.mountain.common.mapper;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<Class, JAXBContext> jaxbContexts = new ConcurrentHashMap<Class, JAXBContext>();/** * 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<CollectionWrapper> wrapperElement = new JAXBElement<CollectionWrapper>(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> T fromXml(String xml, Class<T> 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 {@XmlAnyElementprotected Collection<?> collection;}}

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


package com.gs.mountain.test.xml;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<String> hobby = new ArrayList();        hobby.add("篮球");        hobby.add("音乐");        hobby.add("乒乓球");        List<Student> 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<School> listSchool=new ArrayList<School>();        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"?><schoolList>    <list>        <address>成都市武侯区天府五街</address>        <level>高级中学</level>        <name>华阳中学</name>        <popular>5000</popular>        <Student name="张三" number="10001" sex="男">            <className>尖子班</className>            <hobbys>                <hobby>篮球</hobby>                <hobby>音乐</hobby>                <hobby>乒乓球</hobby>            </hobbys>        </Student>        <Student name="李四" number="10002" sex="男">            <className>普通班</className>            <hobbys>                <hobby>篮球</hobby>                <hobby>音乐</hobby>                <hobby>乒乓球</hobby>            </hobbys>        </Student>        <Student name="莉莉" number="10003" sex="女">            <className>普通班</className>            <hobbys>                <hobby>篮球</hobby>                <hobby>音乐</hobby>                <hobby>乒乓球</hobby>            </hobbys>        </Student>    </list>    <list>        <address>成都市武侯区天府五街</address>        <level>高级中学</level>        <name>华阳中学</name>        <popular>5000</popular>        <Student name="张三" number="10001" sex="男">            <className>尖子班</className>            <hobbys>                <hobby>篮球</hobby>                <hobby>音乐</hobby>                <hobby>乒乓球</hobby>            </hobbys>        </Student>        <Student name="李四" number="10002" sex="男">            <className>普通班</className>            <hobbys>                <hobby>篮球</hobby>                <hobby>音乐</hobby>                <hobby>乒乓球</hobby>            </hobbys>        </Student>        <Student name="莉莉" number="10003" sex="女">            <className>普通班</className>            <hobbys>                <hobby>篮球</hobby>                <hobby>音乐</hobby>                <hobby>乒乓球</hobby>            </hobbys>        </Student>    </list>    <list>        <address>成都市武侯区天府五街</address>        <level>高级中学</level>        <name>华阳中学</name>        <popular>5000</popular>        <Student name="张三" number="10001" sex="男">            <className>尖子班</className>            <hobbys>                <hobby>篮球</hobby>                <hobby>音乐</hobby>                <hobby>乒乓球</hobby>            </hobbys>        </Student>        <Student name="李四" number="10002" sex="男">            <className>普通班</className>            <hobbys>                <hobby>篮球</hobby>                <hobby>音乐</hobby>                <hobby>乒乓球</hobby>            </hobbys>        </Student>        <Student name="莉莉" number="10003" sex="女">            <className>普通班</className>            <hobbys>                <hobby>篮球</hobby>                <hobby>音乐</hobby>                <hobby>乒乓球</hobby>            </hobbys>        </Student>    </list></schoolList>