JAXB(Java Architecture for XML Binding) 是一个业界的标准,是用于 XML 绑定的 Java 体系结构(JAXB)是允许将 Java 类映射到 XML 表示形式的软件框架。 JAXB 支持将 Java 对象编组为 XML,然后将 XML 解组为 Java 对象。
注意:JDK11及以上已经移除JAXB,需要引入相应的包。
创建 java对象 Book
package com.fan.esjavaapi.bean;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType;
/**
* @XmlRootElement(name = "book")
* 类级别的注解,将类映射为xml全局元素,也就是根元素,book为生成的元素名(标签名)
*/
@XmlRootElement(name = "book")
/**
* 通过 @XmlType的 propOrder属性,定义子元素的顺序
*/
@XmlType(propOrder = { "name", "publisher", "isbn" })
public class Book {
private String name;
private String author;
private String publisher;
private String isbn;
public Book(String s, String s1, String s2, String s3) {
this.name = s;
this.author = s1;
this.publisher = s2;
this.isbn = s3;
}
public Book() {
}
/**
* 修改元素名
* name指定元素名,如果没有指定则默认使用字段名或get/set方法去掉前缀剩下部分小写作为元素名
* nillable属性可以指定元素的文本值是否可以为空,默认为false
* required属性可以指定该元素是否必须出现,默认为false
* defaultValue属性可以指定该元素默认的文本值
* namespace属性可以指定该元素所属的命名空间
*/
@XmlElement(name = "title",required = true)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
/**
* @XmlTransient
* 修饰 类,字段,方法级别的注解。可使JAXB在映射xml元素时忽略被注解的类,字段,get/set对应字段
* 需要注意的是该注解与所有其他JAXB注释相互排斥,也就是说与其他注释连用就会报错。
*/
@XmlTransient
public void setAuthor(String author) {
this.author = author;
}
public String getPublisher() {
return publisher;
}
public void setPublisher(String publisher) {
this.publisher = publisher;
}
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("Book{");
sb.append("name='").append(name).append('\'');
sb.append(", author='").append(author).append('\'');
sb.append(", publisher='").append(publisher).append('\'');
sb.append(", isbn='").append(isbn).append('\'');
sb.append('}');
return sb.toString();
}
}
生成 xml文件操作
package com.fan.esjavaapi.api;
import com.fan.esjavaapi.bean.Book;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import java.io.File;
public class javaAPITest {
public static void main(String[] args) {
Book book = new Book();
book.setName("十万个为什么");
book.setAuthor("埃斯托洛凡");
book.setIsbn("10110");
book.setPublisher("人民出版社");
File file = new File("D:\\book.xml");
JAXBContext jc = null;
try {
//根据Book类生成上下文对象
jc = JAXBContext.newInstance(Book.class);
//从上下文中获取Marshaller对象,用作将bean编组(转换)为xml
Marshaller ma = jc.createMarshaller();
//以下是为生成xml做的一些配置
//格式化输出,即按标签自动换行,否则就是一行输出
ma.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
//设置编码(默认编码就是utf-8)
ma.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
//是否省略xml头信息,默认不省略(false)
ma.setProperty(Marshaller.JAXB_FRAGMENT, false);
//编组
ma.marshal(book, file);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
生成的xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<book>
<title>十万个为什么</title>
<publisher>人民出版社</publisher>
<isbn>10110</isbn>
</book>
注意:这里我使用 @XmlTransient 注解给 author 字段添加并不起作用!给 setAuthor 方法加则可以。大家使用的时候尽量给 get/set方法上加。并且给字段添加 @XmlElement(name="XXX") 自定义元素名称报错:
com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
类的两个属性具有相同名称 "name"
解决方案:
在类头加上:@XmlAccessorType(value = XmlAccessType.FIELD)
原因:@XmlAccessorType的默认访问级别是XmlAccessType.PUBLIC_MEMBER,如果java对象中的private成员变量设置了public权限的getter/setter方法,就不要在private变量上使用@XmlElement和@XmlAttribute注解,否则在由java对象生成xml时会报同一个属性在java类里存在两次的错误。所以尽量给 get/set方法上加。
给字段加这样定义java对象:
package com.fan.esjavaapi.bean;
import javax.xml.bind.annotation.*;
/**
* @XmlRootElement(name = "book")
* 类级别的注解,将类映射为xml全局元素,也就是根元素,book为生成的元素名(标签名)
*/
@XmlRootElement(name = "book")
/**
* @XmlAccessorType(value = XmlAccessType.FIELD)
* @XmlAccessorType的默认访问级别是XmlAccessType.PUBLIC_MEMBER,
* 如果java对象中的private成员变量设置了public权限的getter/setter方法,
* 就不要在private变量上使用@XmlElement和@XmlAttribute注解,
* 否则在由java对象生成xml时会报同一个属性在java类里存在两次的错误
*/
@XmlAccessorType(value = XmlAccessType.FIELD)
public class Book {
@XmlElement(name = "title")
private String name;
@XmlTransient
private String author;
private String publisher;
private String isbn;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getPublisher() {
return publisher;
}
public void setPublisher(String publisher) {
this.publisher = publisher;
}
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
}
效果相同!
// 将 xml 转为 java对象
File file = new File("D:\\book.xml");
JAXBContext jc = null;
try {
jc = JAXBContext.newInstance(Book.class);
Unmarshaller uma = jc.createUnmarshaller();
Book book = (Book) uma.unmarshal(file);
System.out.println(book);
} catch (JAXBException e) {
e.printStackTrace();
}
结果:
Book{name='十万个为什么', author='null', publisher='人民出版社', isbn='10110'}
创建 书店类,用来存放多个书籍
package com.fan.esjavaapi.bean;
import java.util.ArrayList;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
/**
* namespace
* 指定该元素所属的命名空间
*/
@XmlRootElement(namespace = "com.fan")
public class BookStore {
// @XmlElementWrapper注释在 book 元素周围定义了包装元素。
@XmlElementWrapper(name = "bookList")
//@XmlElement注解定义包装器内的 XML 元素的名称。
@XmlElement(name = "book")
private ArrayList<Book> bookList;
private String name;
private String location;
public void setBookList(ArrayList<Book> bookList) {
this.bookList = bookList;
}
public ArrayList<Book> getBooksList() {
return bookList;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
}
生成书店xml:
package com.fan.esjavaapi.api;
import com.fan.esjavaapi.bean.Book;
import com.fan.esjavaapi.bean.BookStore;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import java.io.File;
import java.util.ArrayList;
public class javaAPITest {
public static void main(String[] args) {
Book book = new Book();
book.setName("十万个为什么");
book.setAuthor("埃斯托洛凡");
book.setIsbn("10110");
book.setPublisher("人民出版社");
Book book2 = new Book();
book2.setName("海底世界");
book2.setAuthor("佗罗夫司机");
book2.setIsbn("10111");
book2.setPublisher("人民出版社");
BookStore bookStore = new BookStore();
bookStore.setName("新华书店");
bookStore.setLocation("桥西区东大街");
ArrayList<Book> bookList = new ArrayList<>();
bookList.add(book);
bookList.add(book2);
bookStore.setBookList(bookList);
File file = new File("D:\\book.xml");
JAXBContext jc = null;
try {
//根据Book类生成上下文对象
jc = JAXBContext.newInstance(BookStore.class);
//从上下文中获取Marshaller对象,用作将bean编组(转换)为xml
Marshaller ma = jc.createMarshaller();
//以下是为生成xml做的一些配置
//格式化输出,即按标签自动换行,否则就是一行输出
ma.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
//设置编码(默认编码就是utf-8)
ma.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
//是否省略xml头信息,默认不省略(false)
ma.setProperty(Marshaller.JAXB_FRAGMENT, false);
//编组
ma.marshal(bookStore, file);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
结果:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:bookStore xmlns:ns2="com.fan">
<bookList>
<book>
<title>十万个为什么</title>
<publisher>人民出版社</publisher>
<isbn>10110</isbn>
</book>
<book>
<title>海底世界</title>
<publisher>人民出版社</publisher>
<isbn>10111</isbn>
</book>
</bookList>
<location>桥西区东大街</location>
<name>新华书店</name>
</ns2:bookStore>
@XmlJavaTypeAdapter
解决java日期(Date),数字(Number)格式化问题。
该注解的用法就是自定义适配器并继承XmlAdapter类,实现里面的marshal和unmarshal方法,解决日期数字格式化问题。
自定义设配器并继承XmlAdapter
package com.fan.esjavaapi.adpter;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateAdapter extends XmlAdapter<String, Date> {
private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd");
@Override
public Date unmarshal(String date) throws Exception {
return SDF.parse(date);
}
@Override
public String marshal(Date date) throws Exception {
return SDF.format(date);
}
}
在Book类中添加 日期成员变量
public Date getData() {
return data;
}
public void setData(Date data) {
this.data = data;
}
@XmlJavaTypeAdapter(DateAdapter.class)
private Date data;
生成的时候填充日期:
book.setData(new Date());
book2.setData(new Date());
结果:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:bookStore xmlns:ns2="com.fan">
<bookList>
<book>
<title>十万个为什么</title>
<publisher>人民出版社</publisher>
<isbn>10110</isbn>
<data>2022-12-10</data>
</book>
<book>
<title>海底世界</title>
<publisher>人民出版社</publisher>
<isbn>10111</isbn>
<data>2022-12-10</data>
</book>
</bookList>
<location>桥西区东大街</location>
<name>新华书店</name>
</ns2:bookStore>
参考连接: