JAXB(Java API for XML Binding),提供了一个快速便捷的方式将Java对象与XML进行转换。在JAX-WS(Java的WebService规范之一)中,JDK1.6自带的版本JAX-WS2.1,其底层支持就是JAXB。
JAXB可以实现Java对象与XML的相互转换,在JAXB中,将一个Java对象转换为XML的过程称之为Marshal,将XML转换为Java对象的过程称之为UnMarshal。我们可以通过在 Java 类中标注注解的方式将一个Java对象绑定到一段XML,也就是说,在Java类中标注一些注解,这些注解定义了如何将这个类转换为XML,怎么转换,以及一段XML如何被解析成这个类所定义的对象;也可以使用JAXB的XJC工具,通过定义schema的方式实现Java对象与XML的绑定。
项目整体结构如下:
1.建立三个实体
People.java
package com.hys.demo.entity;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "people",namespace="abc")//设置根节点
@XmlAccessorType(XmlAccessType.FIELD)
public class People {
public String id;
public String name;
public int age;
public People() {
}
public People(String id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
TestObj.java
package com.hys.demo.entity;
import java.util.Date;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
@XmlAccessorType(XmlAccessType.FIELD)
public class TestObj {
private long id;
private String name;
private Date birthday;
public TestObj() {
}
public TestObj(long id, String name, Date birthday) {
this.id = id;
this.name = name;
this.birthday = birthday;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
ObjList.java
package com.hys.demo.entity;
import java.util.ArrayList;
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.XmlRootElement;
import com.hys.demo.entity.TestObj;
@XmlRootElement(name = "peoples")
@XmlAccessorType(XmlAccessType.FIELD)
public class ObjList {
@XmlAttribute(name = "size")
private int size;
@XmlElement(name = "people")
private ArrayList objList;
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public ArrayList getObjList() {
return objList;
}
public void setObjList(ArrayList objList) {
this.objList = objList;
}
}
2.Xml文件
test.xml
16817
张三01
2011-12-28
16817
张三02
2011-12-28
16817
张三03
2011-12-28
people.xml
001
灰太狼
22
Java To XML(Marshal)
JaxbWriteXml.java
package com.hys.demo.marshal;
import java.util.ArrayList;
import java.util.Date;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import org.junit.Test;
import com.hys.demo.entity.ObjList;
import com.hys.demo.entity.People;
import com.hys.demo.entity.TestObj;
public class JaxbWriteXml {
public static Marshaller getMarshaller(Class c) throws JAXBException{
JAXBContext context = JAXBContext.newInstance(c);
Marshaller marshaller = context.createMarshaller();
//编码格式
marshaller.setProperty(Marshaller.JAXB_ENCODING,"UTF-8");
//是否格式化生成的xml串
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
//是否省略xml头信息()
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, false);
return marshaller;
}
@Test
public void test_xml() throws JAXBException{
Marshaller marshaller = getMarshaller(People.class);
People people = new People("001","灰太狼",22);
marshaller.marshal(people, System.out);
}
@Test
public void test_xml2() throws JAXBException{
Marshaller marshaller = getMarshaller(ObjList.class);
ArrayList list = new ArrayList();
TestObj testObj1 = new TestObj(111, "灰太狼", new Date());
TestObj testObj2 = new TestObj(222, "灰太狼", new Date());
list.add(testObj1);
list.add(testObj2);
ObjList objlist = new ObjList();
objlist.setObjList(list);
marshaller.marshal(objlist, System.out);
}
}
测试结果1:
001
灰太狼
22
测试结果2:
111
灰太狼
2017-01-11T17:10:01.181+08:00
222
灰太狼
2017-01-11T17:10:01.182+08:00
XML To Java(UnMarshal)
JaxbReadXml.java
package com.hys.demo.unMarshal;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.MessageFormat;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import org.junit.Test;
import com.hys.demo.entity.ObjList;
import com.hys.demo.entity.People;
import com.hys.demo.entity.TestObj;
public class JaxbReadXml {
@SuppressWarnings("unchecked")
public static T readString(Class clazz, String context) throws JAXBException, IOException {
try {
InputStream inputStream = ClassLoader.getSystemResource(context).openStream();
JAXBContext jc = JAXBContext.newInstance(clazz);
Unmarshaller u = jc.createUnmarshaller();
return (T) u.unmarshal(inputStream);
} catch (JAXBException e) {
throw e;
}
}
@SuppressWarnings("unchecked")
public static T readConfig(Class clazz, String config, Object... arguments) throws IOException,
JAXBException {
InputStream is = null;
try {
if (arguments.length > 0) {
config = MessageFormat.format(config, arguments);
}
// logger.trace("read configFileName=" + config);
JAXBContext jc = JAXBContext.newInstance(clazz);
Unmarshaller u = jc.createUnmarshaller();
is = new FileInputStream(config);
return (T) u.unmarshal(is);
} catch (IOException e) {
// logger.trace(config, e);
throw e;
} catch (JAXBException e) {
// logger.trace(config, e);
throw e;
} finally {
if (is != null) {
is.close();
}
}
}
@SuppressWarnings("unchecked")
public static T readConfigFromStream(Class clazz, InputStream dataStream) throws JAXBException {
try {
JAXBContext jc = JAXBContext.newInstance(clazz);
Unmarshaller u = jc.createUnmarshaller();
return (T) u.unmarshal(dataStream);
} catch (JAXBException e) {
// logger.trace(e);
throw e;
}
}
@Test
public void test_xml() throws JAXBException, IOException{
ObjList arrayObj = JaxbReadXml.readString(ObjList.class, "test.xml");
System.out.println(arrayObj.getSize());
for (TestObj testObj : arrayObj.getObjList()) {
System.out.println("姓名:"+testObj.getName()+" 出生日期:"+testObj.getBirthday());
}
}
@Test
public void test_xml1() throws JAXBException, IOException{
People People = JaxbReadXml.readString(People.class, "people.xml");
System.out.println("姓名:"+People.getName()+" 年龄:"+People.getAge());
}
}
测试结果1:
7095
姓名:张三01 出生日期:Wed Dec 28 00:00:00 CST 2011
姓名:张三02 出生日期:Wed Dec 28 00:00:00 CST 2011
姓名:张三03 出生日期:Wed Dec 28 00:00:00 CST 2011
测试结果2:
姓名:灰太狼 年龄:22
其实Marshal和 UnMarshal的过程并不复杂,只需要从JAXBContext中获得Marshaller或Unmarshaller对象,就可以让JAXB帮我们来进行转换了。
我们需要操作的主要内容是定义一个规则,告诉JAXB如何将一个类、按照什么样的格式转换为XML,下面是JAXB中主要的一些注解。
@XmlRootElement 将一个Java类映射为一段XML的根节点
参数:name定义这个根节点的名称;namespace 定义这个根节点命名空间
@XmlAccessorType 定义这个类中的何种类型需要映射到XML。可接收四个参数,分别是:
XmlAccessType.FIELD:映射这个类中的所有字段到XML
XmlAccessType.PROPERTY:映射这个类中的属性(get/set方法)到XML
XmlAccessType.PUBLIC_MEMBER:将这个类中的所有public的field或property同时映射到XML(默认)
XmlAccessType.NONE:不映射
@XmlElement 指定一个字段或get/set方法映射到XML的节点。如,当一个类的XmlAccessorType被标注为PROPERTY时,在某一个没有get/set方法的字段上标注此注解,即可将该字段映射到XML。
参数:defaultValue 指定节点默认值
name 指定节点名称
namespace 指定节点命名空间
required 是否必须(默认为false)
nillable 该字段是否包含nillable="true"属性(默认为false)
type 定义该字段或属性的关联类型
@XmlAttribute 指定一个字段或get/set方法映射到XML的属性。
参数:name 指定属性名称
namespace 指定属性命名空间
required 是否必须(默认为false)
@XmlTransient 定义某一字段或属性不需要被映射为XML。如,当一个类的XmlAccessorType被标注为PROPERTY时,在某一get/set方法的字段上标注此注解,那么该属性则不会被映射。
@XmlType 定义映射的一些相关规则
参数:propOrder 指定映射XML时的节点顺序
factoryClass 指定UnMarshal时生成映射类实例所需的工厂类,默认为这个类本身
factoryMethod 指定工厂类的工厂方法
name 定义XML Schema中type的名称
namespace 指定Schema中的命名空间
@XmlElementWrapper 为数组元素或集合元素定义一个父节点。如,类中有一元素为List items,若不加此注解,该元素将被映射为
这种形式,此注解可将这个元素进行包装,如:
@XmlElementWrapper(name="items") @XmlElement(name="item") public List items;
将会生成这样的XML样式:
@XmlJavaTypeAdapter 自定义某一字段或属性映射到XML的适配器。如,类中包含一个接口,我们可以定义一个适配器(继承自 javax.xml.bind.annotation.adapters.XmlAdapter类),指定这个接口如何映射到XML。
@XmlSchema配置整个包的namespace,这个注解需放在package-info.java文件中。 jaxb编码:
JAXBContext jaxbContext = JAXBContext.newInstance(clazz);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
InputStreamReader reader=newInputStreamReader(inputStream,"GBK"); //在此修改编码
return unmarshaller.unmarshal(reader);
其他:
对于要序列化(marshal)为XML的Java类,绝不能把成员变量声明为public,否则运行将抛出异常com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException。
对于JAXB相关的重要Annotation的声明,如@Xml.....,可以放在成员变量的setter()或getter()方法上,两者中任选其一即可,但决不能放在成员变量上,否则运行将抛出异常com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException
缺省的数据类型绑定
下面的表格列出了JAXB中XML数据类型和Java数据类型的映射。
XML Schema类型 |
Java数据类型 |
xsd:string |
java.lang.String |
xsd:positiveInteger |
java.math.BigInteger |
xsd:int |
int |
xsd:long |
long |
xsd:short |
short |
xsd:decimal |
java.math.BigDecimal |
xsd:float |
float |
xsd:double |
double |
xsd:boolean |
boolean |
xsd:byte |
byte |
xsd:QName |
javax.xml.namespace.QName |
xsd:dateTime |
javax.xml.datatype.XMLGregorianCalendar |
xsd:base64Binary |
byte[] |
xsd:hexBinary |
byte[] |
xsd:unsignedInt |
long |
xsd:unsignedShort |
int |
xsd:unsignedByte |
short |
xsd:time |
javax.xml.datatype.XMLGregorianCalendar |
xsd:date |
javax.xml.datatype.XMLGregorianCalendar |
xsd:g |
javax.xml.datatype.XMLGregorianCalendar |
xsd:anySimpleType |
java.lang.Object |
xsd:anySimpleType |
java.lang.String |
xsd:duration |
javax.xml.datatype.Duration |
xsd:NOTATION |
javax.xml.namespace.QName |