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());

结果:


十万个为什么人民出版社101102022-12-10海底世界人民出版社101112022-12-10桥西区东大街新华书店

参考连接:

Java JAXB 教程|极客教程 (geek-docs.com) 

JAXB常用注解讲解(超详细)_@不会Ayy的拉马尔的博客-CSDN博客_jaxb 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部