什么是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> 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,若不加此注解,该元素将被映射为
<item>...</item> <item>...</item>
设置完@XmlElementWrapper 后会生成这样的XML样式:
<items> <item>...</item> <item>...</item> </items>
10、@XmlJavaTypeAdapter
使用定制的适配器(即扩展抽象类XmlAdapter并覆盖marshal()和unmarshal()方法),以序列化Java类为XML。
比如下面例子对日期格式进行特殊的处理,需要继承xmladapter,从date类型转成string类型
@XmlJavaTypeAdapter(value=JaxbAdapter.class) private Date date; ... public class JaxbAdapter extends XmlAdapter<String, Date> { @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); } }
排序
2.对于所有@XmlElement标注过的属性,必须出现在@XmlType的propOrder列表中。
3.此类可与以下注释一起使用: XmlRootElement
、XmlAccessorOrder
、XmlAccessorType
、 XmlEnum
。但是,当此注释用于枚举类型时,将忽略 XmlAccessorOrder
和 XmlAccessorType
。
测试源码
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> 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<D> getD() { return d; } public void setD(List<D> 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<D> 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> T xml2Object(String xmlStr,Class<T> 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; } } } 结果 <?xml version="1.0" encoding="utf-8" standalone="yes"?> <xml> <B b1="B1">B2</B> <c> <c1>C1</c1> <c2></c2> </c> <Dlist> <d> <d1>d1</d1> <d2>d2</d2> </d> <d> <d1>d1</d1> <d2>d2</d2> </d> </Dlist> </xml> 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
<B b1="B1"> <b3>B3</b3> B2 </B>
Jaxb下载:http://jaxb.java.net
Jaxb官方手册:https://jaxb.java.net/2.2.11/docs/ch03.html
XmlType API:http://www.cjsdn.net/Doc/JDK60/javax/xml/bind/annotation/XmlType.html
Marshaller API:http://www.apihome.cn/api/java/Marshaller.html
XmlAccessType API:
相关阅读:json和xml操作
未经允许请勿转载:程序喵 » 【Java】JAXB操作XML用法详解