JAXB使用教程

JAXB教程

Java爲處理XML文件和結構提供了多種選擇,目前應用最爲普遍的是JAXB工具庫。JAXB表明了Java處理XML文件的事實上標準,它提供了Java對象與XML文本之間互相轉換的功能。從JRE6開始,JAXB就已經成爲了JRE的內置模塊。java

在JAXB以前,Java處理XML的方式只能是使用DOM解析,而採用這種方式並非一個最優的解決方案,由於DOM解析幾乎不能將XML與Java對象映射起來,全部的值類型都只能映射爲String字符串。JAXB爲XML節點和屬性提供了各類面向對象的處理方式,能夠基於自定義類型、註解等方式將XML轉換成Java對象。api

映射

Java對象能夠經過特定的註解或者依照規範被轉換爲XML,這種轉換成爲映射(mapping)。本教程將經過案例向讀者介紹如下內容:app

  • 經過案例的方式展現如何將Java對象轉換爲XML,這被稱之爲marshaling,我將展現如何處理原始數據類型、集合和使用適配器(adapter)來處理更加複雜的類型。
  • 經過案例展現如何將XML轉換爲Java對象,這被稱爲un-marshaling。
  • 詳細介紹JAXB註解的做用
  • 提供對XSDs(XML Schemas)的介紹,XSDs用於驗證XML,這是JAXB提供的一項高級功能
  • 最後,我將介紹幾個經過JAXB處理XML的有用的工具。

Marshal

本部分將介紹如何將Java對象轉換爲XML以及轉換過程當中的注意事項,這項操做被稱之爲Marshaling. 首先,咱們將業務對象的中的Java域與XML中的元素作一一對應。框架

@XmlType( propOrder = { "name", "capital", "foundation", "continent" , "population"} )
@XmlRootElement( name = "Country" )
public class Country
{
    @XmlElement (name = "Country_Population")
    public void setPopulation( int population )
    {
        this.population = population;
    }
    @XmlElement( name = "Country_Name" )
    public void setName( String name )
    {
        this.name = name;
    }
    @XmlElement( name = "Country_Capital" )
    public void setCapital( String capital )
    {
        this.capital = capital;
    }
    @XmlAttribute( name = "importance", required = true )
    public void setImportance( int importance )
    {
        this.importance = importance;
    }
...

這個類中包含了幾個註解,這些註解明確指出了咱們將會建立哪些XML節點。工具

  • @XmlRootElement 表示root元素
  • @XmlElement與setter方法結合使用
  • @XmlAttribute用於爲XML節點添加屬性。這些屬性能夠經過設置required的值來表示是否爲必備的。
  • @XmlType用於明確指示XML元素的排列順序。

那麼,如何將具體的Java對象轉換爲XML呢?對此,咱們能夠建立一個JAXBContext並使用其marshal方法來作個demo。ui

Country spain = new Country();
spain.setName( "Spain" );
spain.setCapital( "Madrid" );
spain.setContinent( "Europe" );
spain.setImportance( 1 );
spain.setFoundation( LocalDate.of( 1469, 10, 19 ) );
spain.setPopulation( 45000000 );
/* init jaxb marshaler */
JAXBContext jaxbContext = JAXBContext.newInstance( Country.class );
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
/* set this flag to true to format the output */
jaxbMarshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, true );
/* marshaling of java objects in xml (output to file and standard output) */
jaxbMarshaller.marshal( spain, new File( "country.xml" ) );
jaxbMarshaller.marshal( spain, System.out );

基本上來講,這個例子的核心就是JAXBContext,JAXBContext提供了marshal、unmarshal的方法,是咱們使用JAXB API的入口。 在咱們的例子中,咱們提供爲JAXBContext實例提供了須要marshal的類,經過如下代碼實現:this

JAXBContext jaxbContext = JAXBContext.newInstance( Country.class );
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();

以上例子的輸出結果應該是這樣的:spa

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Country importance="1">
 <Country_Name>Spain</Country_Name>
 <Country_Capital>Madrid</Country_Capital>
 <Country_Foundation_Date></Country_Foundation_Date>
 <Country_Continent>Europe</Country_Continent>
 <Country_Population>45000000</Country_Population>
</Country>

上面這個例子咱們實現了基本數據類型轉換爲XML的功能,Fundation_Date元素是空的,咱們接下來會介紹如何解決這個問題。code

看上去並不難,JAXB提供了將各類Java對象轉換爲XML的方法,好比將一個List的country轉換爲XML:orm

@XmlRootElement( name = "Countries" )
public class Countries
{
    List countries;
    /**
     * element that is going to be marshaled in the xml
     */
     @XmlElement( name = "Country" )
    public void setCountries( List countries )
    {
        this.countries = countries;
    }
}

經過設置一個List來把集合轉換爲XML。該例子的輸出結果爲:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Countries>
        <Country importance="1">
                <Country_Name>Spain</Country_Name>
                <Country_Capital>Madrid</Country_Capital>
                <Country_Foundation_Date></Country_Foundation_Date>
                <Country_Continent>Europe</Country_Continent>
                <Country_Population>0</Country_Population>
        </Country>
        <Country importance="0">
                <Country_Name>USA</Country_Name>
                <Country_Capital>Washington</Country_Capital>
                <Country_Foundation_Date></Country_Foundation_Date>
                <Country_Continent>America</Country_Continent>
                <Country_Population>0</Country_Population>
        </Country>
</Countries>

處理集合框架的方式有好幾種:

  1. 使用wrapper註解,javax.xml.bind.annotation.XMLElementWrapper註解提供了一種XML包裝器,這個包裝器能夠放置Java集合。
  2. 能夠使用javax.xml.bind.annotation.XMLElements或者javax.xml.bind.annotation.XMLRefs等表示Java集合的註解,可是這種方式缺少靈活性。
  3. 對集合使用容器類,這也是咱們這裏展現的例子所使用的方法。經過將集合設置爲內部類的域,實現Java集合的Marshal。

Un-marshal

這一小節將介紹上一節的逆操做——將XML解析爲Java對象。 假設如下XML是咱們要解析的文本:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Countries>
        <Country>
                <Country_Name>Spain</Country_Name>
                <Country_Capital>Madrid</Country_Capital>
                <Country_Continent>Europe</Country_Continent>
        </Country>
        <Country>
                <Country_Name>USA</Country_Name>
                <Country_Capital>Washington</Country_Capital>
                <Country_Continent>America</Country_Continent>
        </Country>
        <Country>
                <Country_Name>Japan</Country_Name>
                <Country_Capital>Tokyo</Country_Capital>
                <Country_Continent>Asia</Country_Continent>
        </Country>
</Countries>

接下來建立一個程序來讀取這個XML的內容並解析爲Java對象:

File file = new File( "countries.xml" );
JAXBContext jaxbContext = JAXBContext.newInstance( Countries.class );
/**
* the only difference with the marshaling operation is here
*/
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Countries countres = (Countries)jaxbUnmarshaller.unmarshal( file );
System.out.println( countres );

以上的代碼與上一章提供的Java轉爲XML的代碼並無太多的不一樣。經過JAXBContent建立一個Unmarshaller對象,將XML直接轉換爲Java對象。 這個例子中使用到了Country類,其代碼以下:

@XmlType( propOrder = { "name", "capital", "foundation", "continent" , "population"} )
@XmlRootElement( name = "Country" )
public class Country
{
    @XmlElement (name = "Country_Population")
    public void setPopulation( int population )
    {
        this.population = population;
    }
    @XmlElement( name = "Country_Name" )
    public void setName( String name )
    {
        this.name = name;
    }
    @XmlElement( name = "Country_Capital" )
    public void setCapital( String capital )
    {
        this.capital = capital;
    }
    @XmlAttribute( name = "importance", required = true )
    public void setImportance( int importance )
    {
        this.importance = importance;
    }
...

與上一章節中的Country類是如出一轍的。 以上Java代碼的輸出結果以下:

Name: Spain
Capital: Madrid
Europe
Name: USA
Capital: Washington
America
Name: Japan
Capital: Tokyo
Asia

同理,咱們能夠使用相同的方式Unmarshalling其餘的原始數據類型或者集合類型。

適配器(Adapters)

處理沒法直接使用的複雜數據類型的解析和映射時,咱們須要使用適配器的方式來告訴JAXB如何處理這些特定的類型。這裏簡單經過解析和映射java.time.LocalDate的例子來展現JAXB在處理複雜數據類型上的強大功能。

public class DateAdapter extends XmlAdapter{
    public LocalDate unmarshal( String date ) throws Exception
    {
        return LocalDate.parse( date );
    }
    public String marshal( LocalDate date ) throws Exception
    {
       return date.toString();
    }
}

以上代碼展現瞭如何經過javax.xml.bind. annotation.adapters.XmlAdapter對特定的類型進行marshal和unmarshal,在Java代碼中經過如下代碼作映射:

@XmlElement( name = "Country_Foundation_Date" )
@XmlJavaTypeAdapter( DateAdapter.class )
public void setFoundation( LocalDate foundation )
{
    this.foundation = foundation;
}

運行的結果:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Country importance="1">
        <Country_Name>Spain</Country_Name>
        <Country_Capital>Madrid</Country_Capital>
        <Country_Foundation_Date>1469-10-19</Country_Foundation_Date>
        <Country_Continent>Europe</Country_Continent>
        <Country_Population>45000000</Country_Population>
</Country>

經過這種方式,咱們能夠將複雜的類型映射爲XML,咱們只須要實現XmlAdapter接口,並複寫其中的marshal和unmarshal方法便可達到目的。

註解

相關文章
相關標籤/搜索