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<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集合
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类,包含爱好集合和一些基本的属性
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大神提供,很好用(自己看其中的方法,说不定有你需要的)
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. * <p> * 在创建时需要设定所有需要序列化的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 { @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<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>
博主讲解的很详细,知识点罗列的很清晰,可以尝试着写写样例用到工作当中!