目录
JAXB 工具库 简介
1、JAXB(Java Architecture for XML Binding) 提供了Java 对象与 XML 文本之间互相转换的功能。
2、Java 自身为处理 XML 文件和结构提供了多种选择,目前应用最为广泛的是 JAXB 工具库,从 JRE6 开始,JAXB 就已经成为了JRE 的内置模块,在 javax.xml.bind 包下,无需再倒入额外的包。
3、JAXB 为 XML 节点和属性提供了各种面向对象的处理方式,可以基于自定义类型、注解等方式将 XML 转换成 Java 对象。
4、XML(可扩展标记语言)遵循W3C标准,是一种通用的数据交换格式,具有很强的跨平台性,如果数据需要做跨平台传输,那么把数据保存在 XML 文件中是个不错的选择。XML 仅仅是作为一种文档模式的结构化存储,所以并不适用于大数据量的存储。
1)常用 API
javax.xml.bind.JAXBContext (类) | XML 解析的入口,提供了管理实现 JAXB 绑定框架操作所需的 XML/Java 绑定信息的抽象,包括:解组、编组和验证。 |
javax.xml.bind.Marshaller (接口) | 将 Java 内容树序列化为 XML 数据的,称为 编组. |
javax.xml.bind.Unmarshaller (接口) | 将 XML 数据反序列化为 Java 内容树,称为 解组。可在解组时有选择地验证 XML 数据。针对各种不同的输入种类提供各种重载的 unmarshal 方法。 |
2)常用注解
@XmlRootElement | 将 Java 类或枚举映射成 XML 根节点元素,其 name 属性指定根节点名称,不指定默认为类名的小写; 这是唯一一个必须要写的注解,其余注解不写时都有默认处理方式,而 @XmlRootElement 则必须标注,否则抛异常:com.sun.istack.internal.SAXException2: 由于类型 "xxx" 缺少 @XmlRootElement 注释, 无法将该类型编集为元素。写在类上。 |
@XmlElement | 将Java类的属性映射为XML节点元素,其 name 属性可自定义元素名;写在属性的getter或者setter方法上。 |
@XmlAttribute | 将Java类的一个属性映射为XML节点元素的属性,其name属性可自定义属性名;写在属性的getter或者setter方法上。 |
@XmlType | 将Java类或枚举类型映射到XML模式类型,常与@XmlRootElement、@XmlAccessorType共用,其propOrder属性定义属性生成的XML节点顺序;写在类上。 |
@XmlTransient | 用于标识在由Java对象映射XML时,忽略此属性,则生成的XML文件中将不出现此元素。写在属性的getter或者setter方法上。 |
@XmlAccessOrder | 用于控制 JAXB 绑定类中属性和字段的排序。AccessorOrder.ALPHABETICAL—对生成的XML元素按字母顺序排序,XmlAccessOrder.UNDEFINED——不排序(默认值)。如果想指定更细粒度的排序,请使用@XmlType。写在类上。 |
@XmlElementWrapper | 对于数组或集合(即包含多个元素的成员变量),生成一个包装该数组或集合的XML元素(称为包装器)。写在属性的getter或者setter方法上。 |
@XmlJavaTypeAdapter | 自定义适配器(即扩展抽象类XmlAdapter并覆盖marshal()和unmarshal()方法),解决日期(Date),数字(Number)格式化问题;写在属性的getter或者setter方法上。 |
Marshaller 编组/序列化快速入门
1、如下所示准备的 POJO 对象 User 如下,此时只写了必须要添加的 @XmlRootElement 注解在类上。
import javax.xml.bind.annotation.XmlRootElement;
import java.util.Date;
/**
* Created by Administrator on 2019/2/13 0013.
* User 实体
*
* @XmlRootElement 将类或枚举类型映射到 XML 元素,这个注解必须进行显示标注,表示此类/枚举与xml进行映射
* 除此之外的其余注解可写可不写
*/
@XmlRootElement
public class User {
/**
* uID:用户编号
* uName:用户姓名
* sex:性別,true 表示男生、false 表示女生
* birthday:用户生日
*/
private Integer uID;
private String uName;
private Date birthday;
private Boolean sex;
//省略 getter、setter 方法未粘贴
}
2、POJO 到 XML 的转换非常简单,3行核心代码即可搞定:
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import java.util.Date;
import java.util.Random;
import java.util.UUID;
/**
* Created by Administrator on 2019/2/14 0014.
*/
public class JaxbStudy {
public static void main(String[] args) {
try {
/** 准备进行序列化的 POJO 对象数据*/
User user = new User();
user.setuID(new Random().nextInt(10000));
user.setuName("奋六世之余烈");
user.setBirthday(new Date());
user.setSex(true);
/**
* 1、根据 User 类创建 jaxb 新上下文
* JAXBContext 类中重载了多个newInstance方法,其中 -
* public static JAXBContext newInstance( Class... classesToBeBound )是比较常用的一个
*/
JAXBContext jaxbContext = JAXBContext.newInstance(User.class);
/**
* 2、创建一个可以用来将 java 内容树转换为 XML 数据的 Marshaller 对象
* JAXB_FORMATTED_OUTPUT:指定是否使用换行和缩排对已编组 XML 数据进行格式化的属性名称,为 false 或者不写时,编组的结果会是压缩的一行
* Marshaller.JAXB_ENCODING:指定 xml 文件的编码,默认为 UTF-8
* Marshaller.JAXB_FRAGMENT:指定是否省略 xml 文件的头信息<?xml version="1.0" encoding="utf-8"?>,默认或者为false都是显示
*/
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_ENCODING, "utf-8");
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, false);
/**
* 3、将以 user 为根的内容树编组到输出流中。
* Marshaller 中重载了多个 marshal 方法,其中比较常用的是-
* marshal( Object jaxbElement, java.io.OutputStream os )
* marshal( Object jaxbElement, File output )
* marshal( Object jaxbElement, java.io.Writer writer )
*/
marshaller.marshal(user, System.out);//直接输出到控制台中
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
3、运行结果如上,如果想要指定生成的 xml 内容<user>下的元素顺序,则可以在类上指定 @XmlType 注解,使用其 propOrder 属性。
4、public abstract String[] propOrder :在将类映射到 XML 模式复杂类型时,指定 XML 模式元素的顺序。
5、修改 User 类内容如下,其余内容不变:
/**
* Created by Administrator on 2019/2/13 0013.
* User 实体
*
* @XmlRootElement 将类或枚举类型映射到 XML 元素,这个注解必须进行显示标注,表示此类/枚举与xml进行映射
* 除此之外的其余注解可写可不写
* @XmlType propOrder :在将类映射到 XML 模式复杂类型时,指定 XML 模式元素的顺序。默认情况下 propOrder 中的元素名称与个数都必须与类中的一致,只能是顺序不同。
*/
@XmlType(propOrder = {"uID", "uName", "birthday", "sex"})
@XmlRootElement
public class User {
运行结果如下,此时 <user>下的元素顺序与 @XmlType 中 propOrder 指定的一致。
Xml 注解使用
1、这里将介绍 @XmlType、@XmlRootElement、@XmlElement、@XmlTransient 的使用,将 POJO 转换好的 xml 内容直接输出到本地文件中。
2、POJO 对象 User 内容修改如下:
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType;
import java.util.Date;
/**
* Created by Administrator on 2019/2/13 0013.
* User 实体
*
* @XmlRootElement 将类或枚举类型映射到 XML 元素,这个注解必须进行显示标注,表示此类/枚举与xml进行映射,除此之外的其余注解可写可不写。-
* 其 name 属性可以指定 xml 内容根节点元素的名称,默认为类名首字母小写
* @XmlType propOrder :在将类映射到 XML 模式复杂类型时,指定 XML 模式元素的顺序。默认情况下 propOrder 中的元素名称与个数都必须与类中的一致,只能是顺序不同。
* 如果某属性使用 @XmlTransient 排除不进行序列化时,propOrder 属性中也不能再写。
*/
@XmlType(propOrder = {"uName", "birthday", "sex"})
@XmlRootElement(name = "com.lct.jaxb.User")
public class User {
/**
* uID:用户编号
* uName:用户姓名
* sex:性別,true 表示男生、false 表示女生
* birthday:用户生日
*/
private Integer uID;
private String uName;
private Date birthday;
private Boolean sex;
public Date getBirthday() {
return birthday;
}
/**
* @param birthday
* @XmlElement :可以写在属性的 setter、getter 方法上,不要直接写在属性上-
* <p></p>name属性值指定xml中的节点元素名,默认为类的属性名称-
* 当类中的属性未标识 @XmlElement 注解时,则默认会进行 xml 内容映射-
* 如果想不让某个属性进行 xml 元素节点映射,则标识 @XmlTransient 注解
*/
@XmlElement(name = "user_birthday")
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@XmlElement(name = "user_sex")
public Boolean getSex() {
return sex;
}
public void setSex(Boolean sex) {
this.sex = sex;
}
/**
* 如果想不让某个属性进行 xml 元素节点映射,则标识 @XmlTransient 注解,此时生成的xnl内容中不会此属性元素
*
* @XmlTransient 同样可以写在setter、getter 方法上,不要直接写在属性上
* 标识了 @XmlTransient 后,@XmlType(propOrder = {"x"...}) 中则不能再有顺序排列,否则报错
*/
@XmlTransient
public Integer getuID() {
return uID;
}
public void setuID(Integer uID) {
this.uID = uID;
}
public String getuName() {
return uName;
}
public void setuName(String uName) {
this.uName = uName;
}
@Override
public String toString() {
return "User{" +
"birthday=" + birthday +
", uID=" + uID +
", uName='" + uName + '\'' +
", sex=" + sex +
'}';
}
}
3、JAXB 转换代码修改如下:
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import java.io.File;
import java.util.Date;
import java.util.Random;
import java.util.logging.Logger;
public class JaxbStudy {
/**
* 日志记录器
*/
public static final Logger logger = Logger.getGlobal();
public static void main(String[] args) {
try {
/** 准备进行序列化的 POJO 对象数据
* 如果对象某个属性值为 null,则默认情况下,序列化的 xml 结果中不会有此属性元素*/
User user = new User();
user.setuID(new Random().nextInt(10000));
user.setuName("奋六世之余烈");
user.setBirthday(new Date());
user.setSex(null);//为 null 或者未设值时,xml 内容中不会有此属性元素
/**
* 1、根据 User 类创建 jaxb 新上下文
* JAXBContext 类中重载了多个newInstance方法,其中 -
* public static JAXBContext newInstance( Class... classesToBeBound )是比较常用的一个
*/
JAXBContext jaxbContext = JAXBContext.newInstance(User.class);
/**
* 2、创建一个可以用来将 java 内容树转换为 XML 数据的 Marshaller 对象
* JAXB_FORMATTED_OUTPUT:指定是否使用换行和缩排对已编组 XML 数据进行格式化的属性名称,为 false 或者不写时,编组的结果会是压缩的一行
* Marshaller.JAXB_ENCODING:指定 xml 文件的编码,默认为 UTF-8
* Marshaller.JAXB_FRAGMENT:指定是否省略 xml 文件的头信息<?xml version="1.0" encoding="utf-8"?>,默认或者为false都是显示
*/
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_ENCODING, "utf-8");
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, false);
/**
* 3、将以 user 为根的内容树编组到输出流中。
* Marshaller 中重载了多个 marshal 方法,其中比较常用的是-
* marshal( Object jaxbElement, File output )
* marshal( Object jaxbElement, java.io.OutputStream os )
* marshal( Object jaxbElement, java.io.Writer writer )
*/
//marshaller.marshal(user, System.out);//直接输出到控制台中
/**marshal( Object jaxbElement, File output )
* 直接将序列化的xml内容保存到磁盘文件中
* output 文件不存在时会自动生成,其父目录必须存在。
* output 如果已经存在内容,则会进行覆盖
*/
marshaller.marshal(user, new File("E:/wmx/test/1.xml"));
logger.info("POJO 2 Xml 转换完成...");
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
4、运行结果如下:birthday 属性被修改为 user_birthday,uID 属性因为被修饰为 @XmlTransient,所以结果没有,sex 属性因为被设置为 null,所以结果页没有。
一对多关联序列化
·1、一个用户(User)可以有多本书(Book),这里演示关联序列化,其实也很简单,Book 与 User 写法完全一样。这里附带会将介绍 @XmlAccessorOrder、@XmlAttribute 注解的使用。
2、Book 实体内容如下:
import javax.xml.bind.annotation.XmlAccessOrder;
import javax.xml.bind.annotation.XmlAccessorOrder;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
/**
* Created by Administrator on 2019/2/14 0014.
* 书籍实体
*
* @XmlRootElement 将类或枚举类型映射到 XML 根元素,必须要写的注解
* @XmlAccessorOrder :控制 JAXB 绑定类中属性和字段的排序。ALPHABETICAL:类中的字段和属性是按照字母顺序进行排列;UNDEFINED——不排序(默认值)
*/
@XmlAccessorOrder(XmlAccessOrder.ALPHABETICAL)
@XmlRootElement
public class Book {
private Integer bID;
private String bName;
private Float price;
public Integer getbID() {
return bID;
}
/**
* @XmlAttribute: 将Java类的一个属性映射为XML节点元素的属性,其name属性可自定义属性名.
* 可以写在 setter、getter方法上,不要直接写在属性上.
* 结果如:<books bID="862">
*/
@XmlAttribute
public void setbID(Integer bID) {
this.bID = bID;
}
public String getbName() {
return bName;
}
public void setbName(String bName) {
this.bName = bName;
}
public Float getPrice() {
return price;
}
public void setPrice(Float price) {
this.price = price;
}
@Override
public String toString() {
return "Book{" +
"bID=" + bID +
", bName='" + bName + '\'' +
", price=" + price +
'}';
}
}
3、User实体内容如下:
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import java.util.Date;
import java.util.List;
/**
* User 实体
*
* @XmlRootElement 将类或枚举类型映射到 XML 元素,这个注解必须进行显示标注,表示此类/枚举与xml进行映射,除此之外的其余注解可写可不写。-
* 其 name 属性可以指定 xml 内容根节点元素的名称,默认为类名首字母小写
* @XmlType propOrder :在将类映射到 XML 模式复杂类型时,指定 XML 模式元素的顺序。默认情况下 propOrder 中的元素名称与个数都必须与类中的一致,只能是顺序不同。
* 如果某属性使用 @XmlTransient 排除不进行序列化时,propOrder 属性中也不能再写。
*/
@XmlType(propOrder = {"uID", "uName", "birthday", "sex", "books"})
@XmlRootElement
public class User {
/**
* uID:用户编号
* uName:用户姓名
* sex:性別,true 表示男生、false 表示女生
* birthday:用户生日
*/
private Integer uID;
private String uName;
private Date birthday;
private Boolean sex;
/**
* 多本书,同理也可以是 Set、Map、Array等
* 或者单个的 Book,如 private Book book;也是同理
*/
private List<Book> books;
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Boolean getSex() {
return sex;
}
public void setSex(Boolean sex) {
this.sex = sex;
}
public Integer getuID() {
return uID;
}
public List<Book> getBooks() {
return books;
}
public void setBooks(List<Book> books) {
this.books = books;
}
public void setuID(Integer uID) {
this.uID = uID;
}
public String getuName() {
return uName;
}
public void setuName(String uName) {
this.uName = uName;
}
}
4、POJO 转 xml 编组如下:
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.logging.Logger;
public class JaxbStudy {
/**
* 日志记录器
*/
public static final Logger logger = Logger.getGlobal();
public static void main(String[] args) {
try {
//书籍对象列表
List<Book> books = new ArrayList<Book>();
for (int i = 0; i < 2; i++) {
Book book = new Book();
book.setbID(new Random().nextInt(1000));
book.setbName("六脉神剑-" + (i + 1));
book.setPrice(888.88F);
books.add(book);
}
/** 准备进行序列化的 POJO 对象数据
* 如果对象某个属性值为 null,则默认情况下,序列化的 xml 结果中不会有此属性元素*/
User user = new User();
user.setuID(new Random().nextInt(10000));
user.setuName("奋六世之余烈");
user.setBirthday(new Date());
user.setSex(true);//为 null 或者未设值时,xml 内容中不会有此属性元素
user.setBooks(books);
/**
* 1、根据 User 类创建 jaxb 新上下文
* JAXBContext 类中重载了多个newInstance方法,其中 -
* public static JAXBContext newInstance( Class... classesToBeBound )是比较常用的一个
*/
JAXBContext jaxbContext = JAXBContext.newInstance(User.class);
/**
* 2、创建一个可以用来将 java 内容树转换为 XML 数据的 Marshaller 对象
* JAXB_FORMATTED_OUTPUT:指定是否使用换行和缩排对已编组 XML 数据进行格式化的属性名称,为 false 或者不写时,编组的结果会是压缩的一行
* Marshaller.JAXB_ENCODING:指定 xml 文件的编码,默认为 UTF-8
* Marshaller.JAXB_FRAGMENT:指定是否省略 xml 文件的头信息<?xml version="1.0" encoding="utf-8"?>,默认或者为false都是显示
*/
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_ENCODING, "utf-8");
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, false);
/**
* 3、将以 user 为根的内容树编组到输出流中。
* Marshaller 中重载了多个 marshal 方法,其中比较常用的是-
* marshal( Object jaxbElement, File output )
* marshal( Object jaxbElement, java.io.OutputStream os )
* marshal( Object jaxbElement, java.io.Writer writer )
*/
marshaller.marshal(user, System.out);//直接输出到控制台中
/**marshal( Object jaxbElement, File output )
* 直接将序列化的xml内容保存到磁盘文件中
* output 文件不存在时会自动生成,其父目录必须存在。
* output 如果已经存在内容,则会进行覆盖
*/
marshaller.marshal(user, new File("E:/wmx/test/2.xml"));
logger.info("POJO 2 Xml 转换完成...");
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
5、运行结果如下,可以看到此时 book 中的子元素是字典顺序进行排列的:
6、可以看到 list 序列化的结果中,<books>元素名称默认使用的类的属性名称,视觉上没有层次结构,如果想要修改,可以使用集合包装器注解 @XmlElementWrapper 自定义一个包装节点,这样产生的XML文档才更有层次。
7、在 User 类中的修改如下:
/**
* @XmlElement(name = "book") :将xml内容中默认的<books>元素改为 <book>
* @XmlElementWrapper(name = "bookList") :对所有的 <book>元素外面包裹一个<bookList>元素
* @param books
*/
@XmlElementWrapper(name = "bookList")
@XmlElement(name = "book")
public void setBooks(List<Book> books) {
this.books = books;
}
此时运行结果输出如下:
数据格式化处理
1、业务数据中的日期、数值通常是必不可少的,在数据存储的时候,如过需要对日期、数值进行格式化,则需要继承适配器抽象类 XmlAdapter,并覆写其序列化和反序列化的方法。
2、注意:如果序列化的时候使用了适配器格式化,则反序列的时候也必须使用适配器格式化。
3、下面以常用的日期格式化为例,日期格式化处理类如下:
import javax.xml.bind.annotation.adapters.XmlAdapter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Created by Administrator on 2019/2/14 0014.
* 自定义类继承适配器抽象类 public abstract class XmlAdapter<ValueType,BoundType>
*/
public class DateXmlAdapte extends XmlAdapter<String, Date> {
/**
* 解组/反序列化
*/
@Override
public Date unmarshal(String v) throws Exception {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return dateFormat.parse(v);
}
/**
* 编组/序列化
*/
@Override
public String marshal(Date v) throws Exception {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return dateFormat.format(v);
}
}
4、User 实体如下,将适配器通过 @XmlJavaTypeAdapter 注解应用到需要格式化的时间字段上:
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.util.Date;
/**
* User 实体
*
* @XmlRootElement 将类或枚举类型映射到 XML 元素,这个注解必须进行显示标注,表示此类/枚举与xml进行映射
* 除此之外的其余注解可写可不写
*/
@XmlType(propOrder = {"uID", "uName", "birthday", "sex"})
@XmlRootElement
public class User {
/**
* uID:用户编号
* uName:用户姓名
* sex:性別,true 表示男生、false 表示女生
* birthday:用户生日
*/
private Integer uID;
private String uName;
private Date birthday;
private Boolean sex;
public Date getBirthday() {
return birthday;
}
@XmlJavaTypeAdapter(DateXmlAdapte.class)
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Boolean getSex() {
return sex;
}
public void setSex(Boolean sex) {
this.sex = sex;
}
public Integer getuID() {
return uID;
}
public void setuID(Integer uID) {
this.uID = uID;
}
public String getuName() {
return uName;
}
public void setuName(String uName) {
this.uName = uName;
}
}
4、POJO 转 XML 的代码就不反复粘贴了,与上面的都是一样的,运行结果如下:
Unmarshaller 解组/反序列化
1、反序列化与序列化操作完全同理,所以这里将只做简单的演示,注意事项如下:
1、序列化时,如果日期等属性进行了适配器格式化,则反序列化的时候也必须使用适配器格式化,否则属性值会为null。 2、序列化时如果某个属性值未设值,或者为null,则默认xml中不会有此元素,反序列化时属性值也为null。 3、序列化与反序列时的 POJO 内容尽量保持一致,如不能序列化后又将 POJO 对象的注解进行了修改,此时反序列化时极可能出错。 4、如果使用注解的 name 属性修改了默认的元素标签名,则反序列化时也必须与序列化时保持一致,否则会找不到,而使属性值为null。 5、反序列化时即使手动删除了头信息 <?xml version="1.0" encoding="utf-8" standalone="yes"?>也是可以正确执行的。 |
<?xml version="1.0" encoding="utf-8" standalone="yes"?> <user> <birthday>2019-02-14T13:40:12.506+08:00</birthday> <sex>true</sex> <uID>1277</uID> <uName>奋六世之余烈</uName> </user> |
2、序列化 POJO 内容如上,现在来进行反序列化为 POJO 对象:
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import java.io.File;
/**
* Created by Administrator on 2019/2/14 0014.
*/
public class JaxbStudy {
public static void main(String[] args) {
try {
/**
* 1、根据 User 类创建 jaxb 新上下文
* JAXBContext 类中重载了多个newInstance方法,其中 -
* public static JAXBContext newInstance( Class... classesToBeBound )是比较常用的一个
*/
JAXBContext jaxbContext = JAXBContext.newInstance(User.class);
/**
* 2、创建一个可以用来将 XML 数据转换为 java 内容树的 Unmarshaller 对象。
*/
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
/**
* 3、将指定的 XML 数据反序列化为 Java Bean 内容树,重载了多个 unmarshal 方法,常用的如下:
* Object unmarshal( java.io.File f )
* Object unmarshal( java.io.InputStream is )
* Object unmarshal( java.net.URL url )
* Object unmarshal( Reader reader )
*/
User user = (User) unmarshaller.unmarshal(new File("E:/wmx/test/1.xml"));
System.out.println(user);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
3、运行结果如下:
关联对象反序列化
<?xml version="1.0" encoding="utf-8" standalone="yes"?> <user> <uID>8462</uID> <uName>奋六世之余烈</uName> <birthday>2019-02-14T13:35:39.592+08:00</birthday> <sex>true</sex> <bookList> <book bID="651"> <bName>六脉神剑-1</bName> <price>888.88</price> </book> <book bID="902"> <bName>六脉神剑-2</bName> <price>888.88</price> </book> </bookList> </user> |
1、如上所示是之前序列化时写入的内容,编码其实很简单,只要反序列与序列化的时候,保持 POJO 内容一致,则不会出错。
2、反序列化的代码完全一样,这里不再重复粘贴,运行结果如下:
xml 文档数据的修改
1、对于 JAXB 与 XStream 此类直接将 Java Bean 与 XML 进行互相映射的库,对于数据的修改通常采用的都是先将 xml 文本内容全部读取到内存,修改完成后再写回去文本的方式。
2、说白了就是 "先读取整个 xml 文件内容,然后进行修改,修改完成后再进行写入",因为就是普通的先读再写,故不再进行演示。
JDK1.7 JAXB 快捷转换(推荐)
1、从 jdk1.7 开始,直接新增了一个 API 叫 javax.xml.bind.JAXB ,JAXB 对解组和编组的方法进行了更简单的封装,无需再创建JAXBContext 实例,直接通过 JAXB 静态调用相应的工具方法即可。
Modifier and Type | Method and Description |
---|---|
static void | marshal(Object jaxbObject, File xml) 将Java对象树写入XML并将其存储到指定的位置。 |
static void | marshal(Object jaxbObject, OutputStream xml) 将Java对象树写入XML并将其存储到指定的位置。 |
static void | marshal(Object jaxbObject, Result xml) 将Java对象树写入XML并将其存储到指定的位置。 |
static void | marshal(Object jaxbObject, String xml) 将Java对象树写入XML并将其存储到指定的位置。 |
static void | marshal(Object jaxbObject, URI xml) 将Java对象树写入XML并将其存储到指定的位置。 |
static void | marshal(Object jaxbObject, URL xml) 将Java对象树写入XML并将其存储到指定的位置。 |
static void | marshal(Object jaxbObject, Writer xml) 将Java对象树写入XML并将其存储到指定的位置。 |
static <T> T | unmarshal(File xml, 类<T> type) 从给定的XML输入中读取Java对象树。 |
static <T> T | unmarshal(InputStream xml, 类<T> type) 从给定的XML输入中读取Java对象树。 |
static <T> T | unmarshal(Reader xml, 类<T> type) 从给定的XML输入中读取Java对象树。 |
static <T> T | unmarshal(Source xml, 类<T> type) 从给定的XML输入中读取Java对象树。 |
static <T> T | unmarshal(String xml, 类<T> type) 从给定的XML输入中读取Java对象树。 |
static <T> T | unmarshal(URI xml, 类<T> type) 从给定的XML输入中读取Java对象树。 |
static <T> T | unmarshal(URL xml, 类<T> type) 从给定的XML输入中读取Java对象树。 |
2、有了 public final class JAXB extends Object 的这些静态方法,则一步即可搞定 Java POJO 与 XML 的转换,下面简单的演示几项。
序列化
1、User 对象内容如下:
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import java.util.Date;
/**
* Created by Administrator on 2019/2/13 0013.
* User 实体
*
* @XmlRootElement 将类或枚举类型映射到 XML 元素,这个注解必须进行显示标注,表示此类/枚举与xml进行映射
* 除此之外的其余注解可写可不写
*/
@XmlType(propOrder = {"uID", "uName", "birthday", "sex"})
@XmlRootElement
public class User {
/**
* uID:用户编号
* uName:用户姓名
* sex:性別,true 表示男生、false 表示女生
* birthday:用户生日
*/
private Integer uID;
private String uName;
private Date birthday;
private Boolean sex;
//省略 getter、setter 方法未粘贴
}
2、POJO 转 XML JAXB 方式如下:
import javax.xml.bind.JAXB;
import java.io.File;
import java.util.Date;
import java.util.Random;
public class JaxbStudy {
public static void main(String[] args) {
/** 准备进行序列化的 POJO 对象数据*/
User user = new User();
user.setuID(new Random().nextInt(10000));
user.setuName("及至始皇");
user.setBirthday(new Date());
user.setSex(true);
JAXB.marshal(user, new File("E:/wmx/test/4.xml"));//一步搞定,无需再使用 JAXBContext
JAXB.marshal(user, System.out);//输出到控制台看一看
}
}
反序列化
1、这里直接反序列化上面生成好的 4.xml 文件。
import javax.xml.bind.JAXB;
import java.io.File;
/**
* Created by Administrator on 2019/2/14 0014.
*/
public class JaxbStudy {
public static void main(String[] args) {
//反序列化
User user = JAXB.unmarshal(new File("E:/wmx/test/4.xml"), User.class);
System.out.println(user);
}
}