什么是JAXB?
JAXB(Java Architecture for XML Binding) 是一个业界的标准,是一项可以根据XML Schema产生Java类的技术。在JAX-WS(Java的WebService规范之一)中,JAXB可以实现对象和XML之间相互转换。Unmarshaller类管理将XML数据反序列化为新创建的Java内容树的进程,并可在解组时有选择的验证XML数据。Marshaller类负责管理将Java内容树序列化回XML数据的过程。
在JDK1.6时,JAXB 2.0是JDK 1.6的组成部分。JAXB 2.2.3是JDK 1.7的组成部分。
JDK中JAXB相关的重要Class和Interface
1、JAXBContext类,是应用的入口,用于管理XML/Java绑定信息。
2、Marshaller接口,将Java对象序列化为XML数据。
3、Unmarshaller接口,将XML数据反序列化为Java对象。
JDK中JAXB相关的重要Annotation注解
1、@XmlRootElement
说明:将类或枚举类型映射到XML元素,这是xml的入口,根节点,要记得在声明
范围:顶层类,枚举类型
属性说明:name: XML元素的本地名称,namespace: XML元素的名称空间名
2、@XmlElement
说明:将JavaBean属性映射到派生于属性节点名称的XML元素
范围:JavaBean属性、非static(静态)、非transient(瞬时)字段、XmlElements中的程序元素
属性说明:defaultValue:此元素的默认值,
name:xml模式元素的名称,
namespace:xml模式元素的xml目标名称空间,
nillable:是否可以为空,默认false,
required:如果 required() 为 true,则将 Javabean 属性映射到一个 minOccurs="1" 的 XML 模式元素声明。maxOccurs 为 "1" 表示单个赋值的属性,maxOccurs 为 "unbounded" 则表示多个赋值的属性;如果 required() 为 false,则将 Javabean 属性映射到一个 minOccurs="0" 的 XML 模式元素声明。
注意:
如果只有属性,没有get/set方法,xml是不会输出该节点的,需要在属性上设置@XmlElement,如果有get方法要要在get上设置@XmlElement,不然会异常。
3、@XmlElements
说明:多个@XmlElement注解的容器,此注解用于注释JavaBean集合属性(如列表)
属性说明:value:@XmlElement注解集合
例如@XmlElementWrapper(name="DEGREES")
@XmlElements({
@XmlElement(name="Degree",type=Degrees.class),
@XmlElement(name="b",type=String.class)
})
private List degrees;
4、@XmlAttribute
说明:将JavaBean属性映射到XML属性
范围:JavaBean属性、字段
5、@XmlAccessorType
定义映射这个类中的何种类型需要映射到XML。可接收四个参数,分别是:XmlAccessType.FIELD:映射这个类中的所有字段到XML,不需要get/set方法,否则会报错
XmlAccessType.PROPERTY:映射这个类中的属性(get/set方法)到XML,如果没有初始值 或 没有get/set方法,xml不会输出
XmlAccessType.PUBLIC_MEMBER:将这个类中的所有public的field或property同时映射到XML(默认) ,只输出public修饰符的属性,或者是其他修饰符,但必须有 get/set方法
XmlAccessType.NONE:不映射,不输出任何字段内容
6、@XmlTransient
定义某一字段或属性不需要被映射为XML。如当一个类的XmlAccessorType被标注为PROPERTY时,在某一get/set方法的字段上标注此注解,那么该属性则不会被映射。
注意:
测试发现只能设置单独在某一属性出现,不能和其他注解同时存在,否则会发生异常
7、@XmlType
定义映射的一些相关规则propOrder:指定映射XML时的节点顺序,默认是随机的顺序
factoryClass:指定UnMarshal时生成映射类实例所需的工厂类,默认为这个类本身
factoryMethod:指定工厂类的工厂方法
name:定义XML Schema中type的名称 (对应的xsd文件中的type)
namespace:指定Schema中的命名空间
8、@XmlAccessorOrder
控制JAXB 绑定类中属性和字段的排序。其value属性,它有两个属性值:XmlAccessOrder.ALPHABETICAL:对生成的xml元素按字母书序排序,满足基本需求这样就不需要使用propOrder一个个字母排序了
XmlAccessOrder.UNDEFINED:不排序
9、@XmlElementWrapper
为数组元素或集合元素定义一个父节点。
如,类中有一元素为List items,若不加此注解,该元素将被映射为...
...
设置完@XmlElementWrapper后会生成这样的XML样式:
...
...
10、@XmlJavaTypeAdapter
使用定制的适配器(即扩展抽象类XmlAdapter并覆盖marshal()和unmarshal()方法),以序列化Java类为XML。
比如下面例子对日期格式进行特殊的处理,需要继承xmladapter,从date类型转成string类型@XmlJavaTypeAdapter(value=JaxbAdapter.class)
private Date date;
...
public class JaxbAdapter extends XmlAdapter {
@Override
public Date unmarshal(String v) throws Exception {
return null;
}
@Override
public String marshal(Date v) throws Exception {
SimpleDateFormat simple = new SimpleDateFormat("yyyy/MM/dd");
return simple.format(v);
}
}
排序
默认情况下,Jaxb编组出来的xml中的字段顺序是随机的,你可以使用@XmlType的propOrder属性来指定序列化的顺序。
第一步:定义java类时,使用@XmlType(propOrder = { "id", "name", "age","book"})指定输出顺序。
注意:
1.对于@XmlElementWrapper标注的属性,不能出现在@XmlType的propOrder列表中。
2.对于所有@XmlElement标注过的属性,必须出现在@XmlType的propOrder列表中。
测试源码import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.XmlValue;
import net.sf.json.JSONObject;
public class XMLTest3 {
@XmlRootElement(name = "xml")
@XmlAccessorType(XmlAccessType.PROPERTY)
@XmlType
static class A{
private B b;
private C c;
private List d;
@XmlElement(name = "B")
public B getB() {
return b;
}
public void setB(B b) {
this.b = b;
}
public C getC() {
return c;
}
public void setC(C c) {
this.c = c;
}
// 为数组元素或集合元素定义一个父节点
@XmlElementWrapper(name="Dlist")
@XmlElement(name="d")
public List getD() {
return d;
}
public void setD(List d) {
this.d = d;
}
}
static class B {
private String b1;
private String b2;
@XmlAttribute
public String getB1() {
return b1;
}
public void setB1(String b1) {
this.b1 = b1;
}
@XmlValue
public String getB2() {
return b2;
}
public void setB2(String b2) {
this.b2 = b2;
}
}
static class C {
private String c1;
private String c2=""; //想要将空值的xml节点输出来,请将该属性初始化一个空值
public String getC1() {
return c1;
}
public void setC1(String c1) {
this.c1 = c1;
}
public String getC2() {
return c2;
}
public void setC2(String c2) {
this.c2 = c2;
}
}
static class D {
private String d1;
private String d2;
D(){}
D(String d1,String d2){
this.d1 = d1;
this.d2 = d2;
}
public String getD1() {
return d1;
}
public void setD1(String d1) {
this.d1 = d1;
}
public String getD2() {
return d2;
}
public void setD2(String d2) {
this.d2 = d2;
}
}
public static void main(String[] args) throws JAXBException {
A a = new A();
B b = new B();
b.setB1("B1");
b.setB2("B2");
a.setB(b);
C c = new C();
c.setC1("C1");
a.setC(c);
List list = new ArrayList<>();
list.add(new D("d1","d2"));
list.add(new D("d1","d2"));
a.setD(list);
// 构造报文 XML 字符串
String xmlStr = object2Xml(a);
System.out.println(xmlStr);
// XML字符串转JavaBean对象
A a2 = xml2Object(xmlStr, A.class);
System.out.println(a.getB().getB1());
// 不能使用JSONObject, 会有找不到内部类get/set方法异常,解决方法是将内部类提出来
// System.out.println(JSONObject.fromObject(a2));
}
/**
* @param object 对象
* @return 返回xmlStr
*/
public static String object2Xml(Object object) {
try {
StringWriter writer = new StringWriter();
JAXBContext context = JAXBContext.newInstance(object.getClass());
Marshaller marshal = context.createMarshaller();
marshal.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); // 格式化输出
marshal.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");// 编码格式,默认为utf-8
marshal.setProperty(Marshaller.JAXB_FRAGMENT, false);// 是否省略xml头信息
marshal.setProperty(Marshaller.JAXB_ENCODING, "utf-8");
marshal.marshal(object, writer);
return new String(writer.getBuffer());
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* @param xmlStr 字符串
* @param c 对象Class类型
* @return 对象实例
*/
@SuppressWarnings("unchecked")
public static T xml2Object(String xmlStr,Class c) {
try {
JAXBContext context = JAXBContext.newInstance(c);
Unmarshaller unmarshaller = context.createUnmarshaller();
return (T) unmarshaller.unmarshal(new StringReader(xmlStr));
} catch (JAXBException e) { e.printStackTrace(); return null; }
}
}
结果
B2
C1
d1
d2
d1
d2
B1
常见异常com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
If a class has @XmlElement property, it cannot have @XmlValue property.
this problem is related to the following location:
at public java.lang.String com.chinatelecom.web.trade.demo.XMLTest3$B.getB2()
at com.chinatelecom.web.trade.demo.XMLTest3$B
at public com.chinatelecom.web.trade.demo.XMLTest3$B com.chinatelecom.web.trade.demo.XMLTest3$A.getB()
at com.chinatelecom.web.trade.demo.XMLTest3$A
异常解读
遇到此类问题其实很好理解,一个类中是不允许@XmlElement和 @XmlValue两个注解同时存在的,当然也不允许有多个@XmlValue,你肯定没见过生成的格式是下面这种情况,虽然这两个不允许同时存在,但是可以多个@XmlAttribute和一个@XmlValue
B3
B2
XmlAccessType API:
相关阅读:json和xml操作