JAXB(Java Architecture for XML Binding) 是一个业界的标准,是一项可以根据XML Schema产生Java类的技术。该过程中,JAXB也提供了将XML实例文档反向生成Java对象树的方法,并能将Java对象树的内容重新写到XML实例文档。从另一方面来讲,JAXB提供了快速而简便的方法将XML模式绑定到Java表示,从而使得Java开发者在Java应用程序中能方便地结合XML数据和处理函数。简介

JAXB 2.0是JDK 1.6的组成部分。JAXB 2.2.3是JDK 1.7的组成部分。

JAXBContext类,是应用的入口,用于管理XML/Java绑定信息。

Marshaller接口,将Java对象序列化为XML数据。

Unmarshaller接口,将XML数据反序列化为Java对象。

@XmlType,将Java类或枚举类型映射到XML模式类型

@XmlAccessorType(XmlAccessType.FIELD) ,控制字段或属性的序列化。FIELD表示JAXB将自动绑定Java类中的每个非静态的(static)、非瞬态的(由@XmlTransient标注)字段到XML。其他值还有XmlAccessType.PROPERTY和XmlAccessType.NONE。

@XmlAccessorOrder,控制JAXB 绑定类中属性和字段的排序。

@XmlJavaTypeAdapter,使用定制的适配器(即扩展抽象类XmlAdapter并覆盖marshal()和unmarshal()方法),以序列化Java类为XML。

@XmlElementWrapper ,对于数组或集合(即包含多个元素的成员变量),生成一个包装该数组或集合的XML元素(称为包装器)。

@XmlRootElement,将Java类或枚举类型映射到XML元素。

@XmlElement,将Java类的一个属性映射到与属性同名的一个XML元素。

@XmlAttribute,将Java类的一个属性映射到与属性同名的一个XML属性。

其他

对于要序列化(marshal)为XML的Java类,绝不能把成员变量声明为public,否则运行将抛出异常com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException。

对于JAXB相关的重要Annotation的声明,如@Xml.....,可以放在成员变量的setter()或getter()方法上,两者中任选其一即可,但决不能放在成员变量上,否则运行将抛出异常com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException。

使用

"xjc"工具可以用来将XML模式或其他类型模式文件(Java 1.6试验性地支持以及WSDL)转换为Java类。Java类使用javax.xml.bind.annotation包下的Java 标注,例如@XmlRootElement和@XmlElement。XML列表序列表示为java.util.List类型的属性, 通过JAXBContext可以创建Marshallers(将Java对象转换成XML)和Unmarshallers(将XML解析为Java对象)。

此外,JAXB包括了一个"schemagen"工具,能够执行"xjc"的反向操作,通过一组标注的Java类创建一个XML模式。

类型

下面的表格列出了JAXB中XML数据类型和Java数据类型的映射。

XML Schema类型

Java数据类型

xsd:string

java.lang.String

xsd:positiveInteger

java.math.BigInteger

xsd:int

int

xsd:long

long

xsd:short

short

xsd:decimal

java.math.BigDecimal

xsd:float

float

xsd:double

double

xsd:boolean

boolean

xsd:byte

byte

xsd:QName

javax.xml.namespace.QName

xsd:dateTime

javax.xml.datatype.XMLGregorianCalendar

xsd:base64Binary

byte[]

xsd:hexBinary

byte[]

xsd:unsignedInt

long

xsd:unsignedShort

int

xsd:unsignedByte

short

xsd:time

javax.xml.datatype.XMLGregorianCalendar

xsd:date

javax.xml.datatype.XMLGregorianCalendar

xsd:g

javax.xml.datatype.XMLGregorianCalendar

xsd:anySimpleType

java.lang.Object

xsd:anySimpleType

java.lang.String

xsd:duration

javax.xml.datatype.Duration

xsd:NOTATION

javax.xml.namespace.QName

下面按JPA+JAXB来例子说明. 
因此引入jpa的实现包.hibernate-validator随便.做验证用的. 

1

2

3

4

5

6

7

8

9

10

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

 这个是简单的入门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);
 }

实际案例:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

<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示例.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

<?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):

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

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并发处理:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

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的 结构

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

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方法测试:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

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的 结构

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

<?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>