JAXB java類與xml互轉


  JAXB(Java Architecture for XML Binding) 是一個業界的標准,是一項可以根據XML Schema產生Java類的技術。該過程中,JAXB也提供了將XML實例文檔反向生成Java對象樹的方法,並能將Java對象樹的內容重新寫到XML實例文檔。從另一方面來講,JAXB提供了快速而簡便的方法將XML模式綁定到Java表示,從而使得Java開發者在Java應用程序中能方便地結合XML數據和處理函數。


一、先看個簡單的例子

實體類:UserInfo.java 

package com.demo.bean;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.Arrays;

@XmlRootElement
public class UserInfo {
    private int id;
    private String name;
    private String gender;
    private String addr;
    private String[] hobbys;

    public UserInfo() {
    }

    public UserInfo(int id, String name, String gender, String addr, String[] hobbys) {
        this.id = id;
        this.name = name;
        this.gender = gender;
        this.addr = addr;
        this.hobbys = hobbys;
    }
    @XmlElement
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
    @XmlElement
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    @XmlElement
    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }
    @XmlElement
    public String getAddr() {
        return addr;
    }

    public void setAddr(String addr) {
        this.addr = addr;
    }
    //使用@XmlElementWrapper注解后,將會在原xml結點上再包裝一層xml
    //@XmlElementWrapper僅允許出現在集合屬性上
    @XmlElementWrapper(name="allhobbys")
    @XmlElement(name="hobby")
    public String[] getHobbys() {
        return hobbys;
    }

    public void setHobbys(String[] hobbys) {
        this.hobbys = hobbys;
    }

    @Override
    public String toString() {
        return "UserInfo{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                ", addr='" + addr + '\'' +
                ", hobbys=" + Arrays.toString(hobbys) +
                '}';
    }
}

實戰互轉方法

import com.demo.bean.UserInfo;
import org.junit.Test;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.File;
import java.io.StringReader;
import java.io.StringWriter;

public class Test01 {
    @Test
    public void test(){
        UserInfo user = new UserInfo(1,"張三","男","杭州",new String[]{"籃球","音樂"});
        String xmlStr = objToXML(user);
        System.out.println(xmlStr);
        System.out.println("---------------------------------------------------------------");
        UserInfo getUser = (UserInfo)xmlStrToObj(xmlStr,UserInfo.class);
        System.out.println(getUser);
        System.out.println("---------------------------------------------------------------");
        //編組輸出到文件中
        objToXmlFile(user,"E:\\user.xml");
        UserInfo getUser1 = (UserInfo)xmlFileToObj("E:\\user.xml",UserInfo.class);
        System.out.println(getUser1);
    }

    public String objToXML(Object obj){
        try {
            //根據obj類生成上下文對象
            JAXBContext context = JAXBContext.newInstance(obj.getClass());
            //從上下文中獲取Marshaller對象,用作將bean編組(轉換)為xml
            Marshaller marshaller = context.createMarshaller();
            //設置編碼格式(默認編碼就是utf-8)
            marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");//GB2312
            //以下是為生成xml做的一些配置
            //是否格式化生成的xml,即按標簽自動換行,否則就是一行輸出
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.FALSE);
            // 是否省略xml頭部信息,默認不省略(false)
            marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
            StringWriter stringWriter = new StringWriter();
            marshaller.marshal(obj, stringWriter);
            StringBuilder stringBuilders = new StringBuilder();
            return stringBuilders.append(stringWriter).toString();
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return null;
    }

    public void objToXmlFile(Object obj,String fileUrl){
        try {
            File file = new File(fileUrl);
            //根據obj類生成上下文對象
            JAXBContext context = JAXBContext.newInstance(obj.getClass());
            //從上下文中獲取Marshaller對象,用作將bean編組(轉換)為xml
            Marshaller marshaller = context.createMarshaller();
            //設置編碼格式(默認編碼就是utf-8)
            marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");//GB2312
            //以下是為生成xml做的一些配置
            //是否格式化生成的xml,即按標簽自動換行,否則就是一行輸出
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
            // 是否省略xml頭部信息,默認不省略(false)
            marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
            marshaller.marshal(obj,file);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
    }

    public Object xmlStrToObj(String xmlStr,Class objClass){
        try {
            JAXBContext jc = JAXBContext.newInstance(objClass);
            Unmarshaller unmar = jc.createUnmarshaller();
            Object obj = unmar.unmarshal(new StringReader(xmlStr));
            return obj;
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return null;
    }

    public Object xmlFileToObj(String xmlFileUrl,Class objClass){
        try {
            File file = new File(xmlFileUrl);
            JAXBContext jc = JAXBContext.newInstance(objClass);
            Unmarshaller unmar = jc.createUnmarshaller();
            Object obj = unmar.unmarshal(file);
            return obj;
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return null;
    }
}

輸出結果:

生成的user.xml文件

二、常用注解解析

1、@XmlRootElement

作用和用法:

  類級別的注解,將類映射為xml全局元素,也就是根元素。就像spring配置文件中的beans。上面的例子中我將該注解用在了UserInfo類上,生成了<userInfo>根元素。常與@XmlType,@XmlAccessorType,@XmlAccessorOrder連用。

屬性:

  該注解含有name和namespace兩個屬性。namespace屬性用於指定生成的元素所屬的命名空間。name屬性用於指定生成元素的名字,若不指定則默認使用類名小寫作為元素名。修改上面的例子,在該注解上使用name屬性:

 

2、@XmlElement

作用和用法:

  字段,方法,參數級別的注解。該注解可以將被注解的字段(非靜態),或者被注解的get/set方法對應的字段映射為本地元素,也就是子元素。默認使用字段名或get/set方法去掉前綴剩下部分小寫作為元素名(在字段名和get/set方法符合命名規范的情況下)。上面例子中,id、addr、name、gender、hobby 都被映射成了<person>元素的子元素。下文會配合@XmlAccessorType注解詳細講解該注解的用法。常與@XmlValue,@XmlJavaTypeAdapter,@XmlElementWrapper連用。

屬性:

  該注解的屬性常用的屬性有有:name、nillable、required、namespace、defaultValue

  • name屬性可以指定生成元素的名字,同@XmlRootElement注解的name屬性一樣,不再舉例。
  • nillable屬性可以指定元素的文本值是否可以為空,默認為false。
  • required屬性可以指定該元素是否必須出現,默認為false。
  • namespace屬性可以指定該元素所屬的命名空間。
  • defaultValue屬性可以指定該元素默認的文本值。

3、@XmlAttribute

作用和用法:

字段和方法級別的注解。該注解會將字段或get/set方法對應的字段映射成本類對應元素的屬性,屬性名默認使用字段名或get/set方法去掉前綴剩下部分首字母小寫(在字段名和get/set方法符合命名規范的情況下)。修改上面例子:

屬性:

  該注解有name,required,namespace三個屬性。用法和@XmlElement注解相同。

4、@XmlTransient

作用和用法:

  類,字段,方法級別的注解。可使JAXB在映射xml元素時忽略被注解的類,字段,get/set對應字段。需要注意的是該注解與所有其他JAXB注釋相互排斥,也就是說與其他注釋連用就會報錯。修改上面例子:

屬性:

  該注解沒有屬性。

5、@XmlJavaTypeAdapter

作用和用法:

  包、類、字段,方法、參數級別的注解。解決java日期(Date),數字(Number)格式化問題。直接看例子,修改UserInfo類,添加一個Date類型字段:

自定義一個適配器來解決這個問題。該注解的用法就是自定義適配器並繼承XmlAdapter類,實現里面的marshal和unmarshal方法,並在該注解上引用。修改例子:

自定義的DateAdapter:

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

6、@XmlAccessorOrder

作用和用法:

  包和類級別的注解。控制生成元素的順序。

屬性:

  只有一個value屬性,可取的值是一個名為XmlAccessOrder的枚舉類型的兩個值,XmlAccessOrder.ALPHABETICAL 和 XmlAccessOrder.UNDEFINED。默認為XmlAccessOrder.UNDEFINED,代表按照類中字段的順序生成元素的順序。

另一個值則代表按照字母表的順序對生成的元素排序。但奇怪的是,只有jaxb按照field生成元素時,默認值才會生效,否則總是按照字母表的順序排序。

7、@XmlAccessorType

作用和用法:

  包和類級別的注解。javaEE的API對該注解的解釋是:控制字段是否被默認序列化。通俗來講,就是決定哪些字段或哪些get/set方法對應的字段會被映射為xml元素,需要注意的是字段或get/set方法的訪問權限(public/private)會影響字段是否被映射為xml元素,下面會詳細講解。

屬性:

  該注解只有一個value屬性,可取的值是一個名為XmlAccessType的枚舉類型里的值,下面詳細看一下這幾個值分別有什么用:

XmlAccessType.PROPERTY:

1.當使用了該值,只要字段有對應的get/set方法對(注意是成對出現,只有其中一個不會發生映射),不需要使用@XmlElement注解,不論該方法的訪問權限是什么(即使是private),jaxb就會將該字段映射成xml元素。不過最好加上@XmlElement注解,get/set方法任選一個即可,都加上會報錯。

2.若在一個字段有set/get方法對但又在字段上添加@XmlElement注解會報屬性重復的錯誤。

3.若沒有set/get方法對,則需要在字段上使用@XmlElement注解才可以映射為xml元素,否則不會發生映射。

4.若get/set方法上使用了@XmlTransient注解,但想要對應字段發生映射,需要在對應字段上添加@XmlElement注解,此時不會報錯,並將該字段映射為xml元素。


XmlAccessType.FIELD:

1.每個非靜態的字段(無論訪問權限如何)都會被jaxb映射為xml元素,即使沒有get/set方法對,即使沒有使用@XmlElement元素,但最好加上該注解以表明該字段要被映射為xml元素。

2.雖然沒有get/set方法對,也會發生映射,但加上get/set方法對也不會報錯,因為我們經常會使用這兩個方法。但注意,不能再在這兩個方法上使用@XmlElement方法,否則會報屬性重復的錯誤。

3.若在字段上使用了@XmlTransient注解,但還想讓該字段發生映射,需要在該字段對應的get/set方法上添加@XmlElement

 

XmlAccessType.PUBLIC_MEMBER: (該值為默認值):

1.每個訪問權限為public的字段,或者每個訪問權限為public的get/set方法對,都會將字段映射為xml元素,即使不使用@XmlElement,但最好加上。不可同時存在public字段和對應的get/set方法對,不然會報屬性重復的錯誤。

2.若使用@XmlElement注解,需要注意只能在字段或get/set方法添加,兩者任選其一,否則會報屬性重復的錯誤。

3.若字段不為public,get/set方法為public並使用了@XmlTransient,需要在字段上添加@XmlElement才會發生映射。

若字段為public並使用了@XmlTransient,get/set方法對不為public,需要在get/set方法上使用@XmlElement才會映射。


XmlAccessType.NONE:

任何字段,get/set方法對都不會發生映射,除非使用某些注解,如@XmlElement,@XmlElementWrapper等。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM