JAXB是一个非常通用的工业标准,它可以对一个实体类进行配置,指定该对象与XML或JSON格式数据的转换映射。本文将介绍如何不借助第三方工具,直接将Java Object与XML文档进行双向转换的操作。关于JSON格式的转换以及JAXB注解配置的使用,暂不做讨论,将后续再写文章进行整理。
一些如Jackson等著名的第三方工具确实对JAXB提供了非常好的支持,但有的时候引入它们也是一种成本。实际上对于简单的使用场景,我们可以使用javax.xml.bind
包中的工具完成转换操作。
例如有一个Person
类,其JAXB注解配置的代码如下:
package com.tech4j.demo;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Person {
private String name;
private Integer age;
// 省略 Getter Setter
}
非常简单,其中只有一个注解@XmlRootElement
。但是需要特别注意,如果希望对类属性进行JAXB配置,最好将注解写在其对应的Getter方法上,而不要写在类属性上。否则后文使用的JAXBContext
将会报出错误。下面给出一种正确的配置示例:
package com.tech4j.demo;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Person {
private String name;
private Integer age;
@XmlElement(name = "XingMing")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
下面这个工具类提供了fromXml()
方法将XML字符串转换为对象,也提供了反向的toXml()
方法将对象转换为XML字符串:
package com.tech4j.demo;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
public class JaxbUtil {
@SuppressWarnings("unchecked")
public synchronized static <T> T fromXml(String xmlStr,Class<T> _class) {
T result = null;
try {
StringReader reader = new StringReader(xmlStr);
JAXBContext context = JAXBContext.newInstance(_class);
Unmarshaller unmarshaller = context.createUnmarshaller();
Object obj = unmarshaller.unmarshal(reader);
if (!_class.isAssignableFrom(obj.getClass())) {
throw new RuntimeException("转换得到的对象并非指定类型范围内的对象!");
}
result = (T) obj;
reader.close();
} catch (JAXBException | RuntimeException e) {
e.printStackTrace();
}
return result;
}
public synchronized static String toXml(Object obj) {
String xmlStr = null;
try {
JAXBContext context = JAXBContext.newInstance(obj.getClass());
Marshaller marshaller = context.createMarshaller();
StringWriter writer = new StringWriter();
marshaller.marshal(obj,writer);
xmlStr = writer.toString();
writer.close();
} catch (JAXBException | IOException e) {
e.printStackTrace();
}
return xmlStr;
}
}
需要注意其中isAssignableFrom()
方法的使用,它用来通过两个反射对象判断后者能否安全地转换为前者对应的类对象。
如前所述,如果我们将@XmlElement(name = "XingMing")
这个注解写在了Person
的类属性name
上,那么程序将会报出错误,说拥有两个同名的属性name
。错误提示如下所示:
com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
类的两个属性具有相同名称 "name"
this problem is related to the following location:
at public java.lang.String com.tech4j.demo.Person.getName()
at com.tech4j.demo.Person
this problem is related to the following location:
at private java.lang.String com.tech4j.demo.Person.name
at com.tech4j.demo.Person