• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
cnsdhzzl
博客园    首页    新随笔    联系   管理    订阅  订阅
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>

 

posted on 2018-01-31 09:07  cnsdhzzl  阅读(6393)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3