当前位置: 首页 > 工具软件 > JAXB > 使用案例 >

Java之JAXB的介绍与使用

苗冯浩
2023-12-01

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对象:

        // 将 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>

参考连接:

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

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

 类似资料: