Java之JAXB的介绍与使用
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注释相互排斥,也就是说与其他注释连用就会报错。*/@XmlTransientpublic 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;}@Overridepublic 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编组(转换)为xmlMarshaller 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
十万个为什么 人民出版社 10110
注意:这里我使用 @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;@XmlTransientprivate 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对象:
// 将 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 bookList;private String name;private String location;public void setBookList(ArrayList bookList) {this.bookList = bookList;}public ArrayList 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 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编组(转换)为xmlMarshaller 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();}}}
结果:
十万个为什么 人民出版社 10110 海底世界 人民出版社 10111 桥西区东大街 新华书店
补充:
@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 {private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd");@Overridepublic Date unmarshal(String date) throws Exception {return SDF.parse(date);}@Overridepublic 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());
结果:
十万个为什么 人民出版社 10110 2022-12-10海底世界 人民出版社 10111 2022-12-10桥西区东大街 新华书店
参考连接:
Java JAXB 教程|极客教程 (geek-docs.com)
JAXB常用注解讲解(超详细)_@不会Ayy的拉马尔的博客-CSDN博客_jaxb
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
