Jaxb 完全手冊


Jaxb是JavaEE的規范.全稱Java Architecture for XML Binding. 
可以根據XML Schema產生Java類的技術.JAXB也提供了將XML實例文檔反向生成Java對象樹的方法,並能將Java對象樹的內容重新寫到XML實例文檔. 
JAXB 2.0是JDK 1.6的組成部分。JAXB 2.2.3是JDK 1.7的組成部分。在實際使用不需要引入新的jar. 
我一般使用都是配合JPA使用,下面例子也是按JPA+JAXB來說明. 
因此我需要引入jpa的實現包.hibernate-validator隨便.做驗證用的.

<dependency>
    <groupId>org.hibernate.javax.persistence</groupId>
    <artifactId>hibernate-jpa-2.0-api</artifactId>
    <version>1.0.1.Final</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>5.0.1.Final</version>
</dependency>

1. JDK中JAXB相關的重要Class和Interface:

  • JAXBContext類,是應用的入口,用於管理XML/Java綁定信息。
  • Marshaller接口,將Java對象序列化為XML數據。
  • Unmarshaller接口,將XML數據反序列化為Java對象。

http://my.oschina.net/zhaoqian/blog/89763 這個是簡單的入門demo.可以先運行試試,對JAXB有個大概的使用方法.下面例子將是系統正常做的.並對並發性進行處理的一個例子.

2. 常用注解說明

常用的annotation有:
@XmlType
@XmlElement
@XmlRootElement
@XmlAttribute
@XmlAccessorType
@XmlAccessorOrder
@XmlTransient
@XmlJavaTypeAdapter
@Temporal(TemporalType.XXXX) -->JPA中的時間處理注解,非JAXB
@XmlElementWrapper

1.@XmlType
  @XmlType用在class類的注解,常與@XmlRootElement,@XmlAccessorType一起使用。它有三個屬性:name、propOrder、namespace,經常使用的只有前兩個屬性。如:
同時使用了@XmlType(propOrder={})和@XmlAccessorOrder(XmlAccessOrder.ALPHABETICAL)的時候,生成的xml只按照propOrder定義的順序生成元素
@XmlType(name = "basicStruct", propOrder = {
    "intValue",
    "stringArray",
    "stringValue"
)
在使用@XmlType的propOrder 屬性時,必須列出JavaBean對象中的所有屬性,否則會報錯。

2.@XmlRootElement
  @XmlRootElement用於類級別的注解,對應xml的跟元素,常與 @XmlType 和 @XmlAccessorType一起使用。如:
  @XmlType
  @XmlAccessorType(XmlAccessType.FIELD)
  @XmlRootElement
  public class Address {}

3.@XmlElement
  @XmlElement將java對象的屬性映射為xml的節點,在使用@XmlElement時,可通過name屬性改變java對象屬性在xml中顯示的名稱。如:
  @XmlElement(name="Address")  
  private String yourAddress;

4.@XmlAttribute
  @XmlAttribute用於把java對象的屬性映射為xml的屬性,並可通過name屬性為生成的xml屬性指定別名。如:
  @XmlAttribute(name="Country")
  private String state;
 
5.@XmlAccessorType
  @XmlAccessorType用於指定由java對象生成xml文件時對java對象屬性的訪問方式。常與@XmlRootElement、@XmlType一起使用。它的屬性值是XmlAccessType的4個枚舉值,分別為:

  • XmlAccessType.FIELD:java對象中的所有成員變量
  • XmlAccessType.PROPERTY:java對象中所有通過getter/setter方式訪問的成員變量
  • XmlAccessType.PUBLIC_MEMBER:java對象中所有的public訪問權限的成員變量和通過getter/setter方式訪問的成員變量
  • XmlAccessType.NONE:java對象的所有屬性都不映射為xml的元素

注意:@XmlAccessorType的默認訪問級別是XmlAccessType.PUBLIC_MEMBER,因此,如果java對象中的private成員變量設置了public權限的getter/setter方法,就不要在private變量上使用@XmlElement和@XmlAttribute注解,否則在由java對象生成xml時會報同一個屬性在java類里存在兩次的錯誤。同理,如果@XmlAccessorType的訪問權限為XmlAccessType.NONE,如果在java的成員變量上使用了@XmlElement或@XmlAttribute注解,這些成員變量依然可以映射到xml文件。

注意:雖然@XmlAccessorType為XmlAccessType.NONE,但是在java類的私有屬性上加了@XmlAttribute和@XmlElement注解后,這些私有成員會映射生成xml的元素

6.@XmlAccessorOrder
  @XmlAccessorOrder用於對java對象生成的xml元素進行排序。它有兩個屬性值:
  AccessorOrder.ALPHABETICAL:對生成的xml元素按字母書序排序
  XmlAccessOrder.UNDEFINED:不排序

7.@XmlTransient
  @XmlTransient用於標示在由java對象映射xml時,忽略此屬性。即,在生成的xml文件中不出現此元素。

8.@XmlJavaTypeAdapter
  @XmlJavaTypeAdapter常用在轉換比較復雜的對象時,如map類型或者格式化日期等。使用此注解時,需要自己寫一個adapter類繼承XmlAdapter抽象類,並實現里面的方法。
  @XmlJavaTypeAdapter(value=xxx.class),value為自己定義的adapter類
  XmlAdapter 抽象接口如下:

public abstract class XmlAdapter<ValueType,BoundType> {    // Do-nothing constructor for the derived classes.
    protected XmlAdapter() {}
    // Convert a value type to a bound type.
    public abstract BoundType unmarshal(ValueType v);
    // Convert a bound type to a value type.
    public abstract ValueType marshal(BoundType v);
 }

實際案例:

 

<i>package jaxb.shop;
  
import java.util.Date;
import java.text.SimpleDateFormat;
  
import javax.xml.bind.annotation.adapters.XmlAdapter;
  
public class DateAdapter extends XmlAdapter<String, Date> {
  
    private String pattern = "yyyy-MM-dd HH:mm:ss";
    SimpleDateFormat fmt = new SimpleDateFormat(pattern);
      
    @Override
    public Date unmarshal(String dateStr) throws Exception {
          
        return fmt.parse(dateStr);
    }
  
    @Override
    public String marshal(Date date) throws Exception {
          
        return fmt.format(date);
    }
  
}
//用於格式化日期在xml中的顯示格式,並且由xml unmarshal為java對象時,將字符串解析為Date對象</i>

在某個類中如下使用,解析出對應的時間格式.必須重載那2個方法,用於JAXB marshal xml,xml unmarshal object時候使用.

   @XmlJavaTypeAdapter(value=DateAdapter.class)
    private Date purDate;

9.但如果是和JPA一起使用的話,可以使用@Temporal(TemporalType.DATE)來格式時間,默認為TemporalType.TIMESTAMP類型.TemporalType屬性如下:
public enum TemporalType {
    DATE, //java.sql.Date
    TIME, //java.sql.Time
    TIMESTAMP //java.sql.Timestamp
}
java.sql.Date
日期型,精確到年月日,例如“2008-08-08”
java.sql.Time
時間型,精確到時分秒,例如“20:00:00”
java.sql.Timestamp
時間戳,精確到納秒,例如“2008-08-08 20:00:00.000000001”

 

10.在JAXB標准中,@XmlElementWrapper注解表示生成一個包裝 XML 表示形式的包裝器元素。 此元素主要用於生成一個包裝集合的包裝器 XML 元素。
注:@XmlElementWrapper僅允許出現在集合屬性上。最后的案例將使用這個注解.

3. 最終案例(模擬XML--系統 --DB)

 

例子XML示例.

<?xml version="1.0" encoding="utf-8"?>
<userinfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <id>110</id>
    <name>Credo</name>
    <address>China BeiJing</address>
    <job>programmer</job>
    <overinfos>
        <overinfo>
            <hobby>Accompany my girlfriend.</hobby>
            <!--開始日期 dateTime-->
            <beginDate>2009-06-02T12:00:00</beginDate>
            <!--結束日期 dateTime-->
            <endDate>2109-06-02T12:00:00</endDate>
        </overinfo>
        <overinfo>
            <hobby>Write some code.</hobby>
            <!--開始日期 dateTime-->
            <beginDate>2009-06-02T12:00:00</beginDate>
            <!--結束日期 dateTime-->
            <endDate>2029-06-02T12:00:00</endDate>
        </overinfo>
    </overinfos>
</userinfo>

Model層(JAXB+JPA):

package org.credo.jaxb.model;
import java.io.Serializable;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlElements;
import javax.xml.bind.annotation.XmlRootElement;
import org.hibernate.validator.constraints.Length;
/**
 * @author Credo
 */
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@Entity
@Table(name = "USERINFO")
public class Userinfo implements Serializable{
     
    private static final long serialVersionUID = 7870351249722416047L;
     
    @Id
    @Column(name = "ID", nullable = false)
    private Long id;
     
    @Column(name = "NAME", length = 50)
    @Length(max = 50)
    private String name;
     
    @Column(name = "ADDRESS", length = 50)
    @Length(max = 50)
    private String address;
     
    @Column(name = "JOB", length = 50)
    @Length(max = 50)
    private String job;
     
    @XmlElementWrapper(name = "overinfos")
    @OneToMany(cascade = CascadeType.ALL)
    @XmlElements(value = { @XmlElement(name = "overinfo", type = Overinfo.class) })
    private List<Overinfo> overinfos;
     
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    public String getJob() {
        return job;
    }
    public void setJob(String job) {
        this.job = job;
    }
    public List<Overinfo> getOverinfos() {
        return overinfos;
    }
    public void setOverinfos(List<Overinfo> overinfos) {
        this.overinfos = overinfos;
    }
     
}

Overinfo.class

package org.credo.jaxb.model;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "overinfo")
@Entity
@Table(name = "OVERINFO")
public class Overinfo implements Serializable {
    private static final long serialVersionUID = 2579971237985854291L;
    @XmlTransient
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ID")
    private Long id;
     
    @XmlTransient
    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "UserinfoId")
    private Userinfo userinfo;
     
    @Column(name = "hobby", length = 20)
    private String hobby;
     
    @Temporal(TemporalType.DATE)
    @Column(name = "beginDate", length = 20)
    private Date beginDate;
     
    @Temporal(TemporalType.DATE)
    @Column(name = "endDate", length = 20)
    private Date endDate;
    public String getHobby() {
        return hobby;
    }
    public void setHobby(String hobby) {
        this.hobby = hobby;
    }
    public Date getBeginDate() {
        return beginDate;
    }
    public void setBeginDate(Date beginDate) {
        this.beginDate = beginDate;
    }
    public Date getEndDate() {
        return endDate;
    }
    public void setEndDate(Date endDate) {
        this.endDate = endDate;
    }
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public Userinfo getUserinfo() {
        return userinfo;
    }
    public void setUserinfo(Userinfo userinfo) {
        this.userinfo = userinfo;
    }
}

JAXB並發處理:

package org.credo.jaxb;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
public final class JAXBCache {
    private static final JAXBCache instance = new JAXBCache();
    private final ConcurrentMap<String, JAXBContext> contextCache = new ConcurrentHashMap<String, JAXBContext>();
    private JAXBCache() {
    }
    public static JAXBCache instance() {
        return instance;
    }
    JAXBContext getJAXBContext(Class<?> clazz) throws JAXBException {
        JAXBContext context = contextCache.get(clazz.getName());
        if ( context == null )
        {
            context = JAXBContext.newInstance(clazz);
            contextCache.putIfAbsent(clazz.getName(), context);
        }
        return context;
    }
}

JAXBExportSchema 導出JAXB的 class的 結構

package org.credo.jaxb;
import java.io.File;
import java.io.IOException;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.SchemaOutputResolver;
import javax.xml.transform.Result;
import javax.xml.transform.stream.StreamResult;
import org.credo.jaxb.model.Userinfo;
/**
 * JAXB 導出Schema。
 *
 * @author: Credo
 * @date: 2013-6-25
 */
public class JAXBExportSchema {
    public static void main(String[] args) {
        JAXBContext jct;
        try
        {
            jct = JAXBContext.newInstance(Userinfo.class);
            jct.generateSchema(new Resolver());
        }
        catch ( Exception ex )
        {
            ex.printStackTrace();
        }
    }
}
class Resolver extends SchemaOutputResolver {
    @Override
    public Result createOutput(String namespaceUri, String suggestedFileName) throws IOException {
        File file = new File("d:\\", suggestedFileName);
        StreamResult result = new StreamResult(file);
        result.setSystemId(file.toURI().toURL().toString());
        return result;
    }
}

JAXBUtil以及main方法測試:

package org.credo.jaxb;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import org.apache.commons.io.IOUtils;
import org.credo.jaxb.model.Overinfo;
import org.credo.jaxb.model.Userinfo;
/**
 * marshal對象和unmarshal對象都是由JAXBContext創建.所以一開始需要初始化JAXBContext.
 * @author Credo
 */
public class JAXBUtil {
    /**
     * 生成xml文件的二進制數據
     * @param obj 對象
     */
    public static byte[] marshal(Object obj) throws JAXBException {
        JAXBContext context = JAXBCache.instance().getJAXBContext(obj.getClass());
        Marshaller m = context.createMarshaller();
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        m.marshal(obj, outputStream);
        byte[] result = outputStream.toByteArray();
        return result;
    }
    /**
     * @param data xml stream
     * @param classe 類
     * @return jaxb生成xml的java 類對象
     */
    public static Object unmarshal(byte[] data, Class<?> classe) throws JAXBException {
        JAXBContext context = JAXBCache.instance().getJAXBContext(classe);
        Unmarshaller m = context.createUnmarshaller();
        ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
        Object obj = m.unmarshal(inputStream);
        return obj;
    }
    /**
     * @param data xml stream
     * @param classe 類
     * @return jaxb生成xml的java 類對象
     */
    public static Object unmarshal(InputStream in, Class<?> classe) throws JAXBException, IOException {
        JAXBContext context = JAXBCache.instance().getJAXBContext(classe);
        byte[] data = IOUtils.toByteArray(in);
        Unmarshaller m = context.createUnmarshaller();
        ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
        Object obj = m.unmarshal(inputStream);
        return obj;
    }
    public static void main(String[] args) throws JAXBException {
        Userinfo userinfo = new Userinfo();
        userinfo.setId(Long.valueOf(11));
        List<Overinfo> list = new ArrayList<Overinfo>();
        Overinfo e = new Overinfo();
        e.setHobby("陪女友");
        list.add(e);
        Overinfo e1 = new Overinfo();
        e1.setHobby("寫代碼");
        list.add(e1);
        userinfo.setOverinfos(list);
        byte[] b = JAXBUtil.marshal(userinfo);
        System.out.println(new String(b));
        userinfo = (Userinfo) JAXBUtil.unmarshal(b, Userinfo.class);
        System.out.println(userinfo.getOverinfos().get(0).getHobby());
    }
}

就不說明了,仔細看代碼的,一會就明白了.不看的運行下也明白了.下面是上面main方法測試的輸出結果:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<userinfo>
    <id>11</id>
    <overinfos>
        <overinfo>
            <hobby>陪女友</hobby>
        </overinfo>
        <overinfo>
            <hobby>寫代碼</hobby>
        </overinfo>
    </overinfos>
</userinfo>

陪女友

下面是使用JAXBExportSchema 導出JAXB的 class的 結構

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="userinfo" type="userinfo"/>
  <xs:complexType name="userinfo">
    <xs:sequence>
      <xs:element name="id" type="xs:long" minOccurs="0"/>
      <xs:element name="name" type="xs:string" minOccurs="0"/>
      <xs:element name="address" type="xs:string" minOccurs="0"/>
      <xs:element name="job" type="xs:string" minOccurs="0"/>
      <xs:element name="overinfos" minOccurs="0">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="overinfo" type="overinfo" minOccurs="0" maxOccurs="unbounded"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="overinfo">
    <xs:sequence>
      <xs:element name="hobby" type="xs:string" minOccurs="0"/>
      <xs:element name="beginDate" type="xs:dateTime" minOccurs="0"/>
      <xs:element name="endDate" type="xs:dateTime" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>
</xs:schema>

 


免責聲明!

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



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