JAXB—Java类与XML文件之间转换

简介

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

一、JAXB使用

一个简单的例子:

Person.class:

@XmlRootElement
public class Person {
private int id;
private String name;
private String gender;
private String addr;
private String area; public Person() {
} public Person(String name, String gender, String addr, String area) {
this.name = name;
this.gender = gender;
this.addr = addr;
this.area = area;
} public int getId() {
return id;
} @XmlElement
public void setId(int id) {
this.id = id;
} public String getName() {
return name;
} @XmlElement
public void setName(String name) {
this.name = name;
} public String getGender() {
return gender;
} @XmlElement
public void setGender(String gender) {
this.gender = gender;
} public String getAddr() {
return addr;
} @XmlElement
public void setAddr(String addr) {
this.addr = addr;
} public String getArea() {
return area;
} @XmlElement
public void setArea(String area) {
this.area = area;
} @Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
", gender='" + gender + '\'' +
", addr='" + addr + '\'' +
", area='" + area + '\'' +
'}';
}
}

Test:


public class JAXBTest {
@Test
public void generateXML() {
Person person = new Person("abc", "男", "北京", "朝阳区"); File file = new File("E:\\person.xml");
JAXBContext jc = null;
try {
//根据Person类生成上下文对象
jc = JAXBContext.newInstance(Person.class);
//从上下文中获取Marshaller对象,用作将bean编组(转换)为xml
Marshaller ma = jc.createMarshaller();
//以下是为生成xml做的一些配置
//格式化输出,即按标签自动换行,否则就是一行输出
ma.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
//设置编码(默认编码就是utf-8)
ma.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
//是否省略xml头信息,默认不省略(false)
ma.setProperty(Marshaller.JAXB_FRAGMENT, false); //编组
ma.marshal(person, file);
} catch (JAXBException e) {
e.printStackTrace();
}
} @Test
public void generateBean() {
File file = new File("E:\\person.xml");
JAXBContext jc = null;
try {
jc = JAXBContext.newInstance(Person.class);
Unmarshaller uma = jc.createUnmarshaller();
Person person = (Person) uma.unmarshal(file);
System.out.println(person);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}

测试结果:

generateXML():



此xml相当于该xsd文件:


<xs:element name="person">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:string" name="addr" minOccurs="0"/>
<xs:element type="xs:string" name="area" minOccurs="0"/>
<xs:element type="xs:string" name="gender" minOccurs="0"/>
<xs:element type="xs:int" name="id" minOccurs="0"/>
<xs:element type="xs:string" name="name" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>

generateBean():

注:从jdk1.7开始,JAXB就对解组和编组的方法进行了更简单的封装,所以实际项目中除非自己要进行个性化设置,否则大可不用自己再创建JAXBContext实例,直接通过JAXB静态调用相应的工具方法就行了,于是上面的测试方法可以写的更简练些:

public class JAXBTest {
@Test
public void generateXML() {
Person person = new Person("abc", "男", "北京", "朝阳区");
File file = new File("E:\\person.xml");
JAXB.marshal(person, file);
} @Test
public void generateBean() {
File file = new File("E:\\person.xml");
Person person = JAXB.unmarshal(file, Person.class); System.out.println(person);
}
}

二、JAXB常用注解

1、@XmlRootElement:

(1)作用和用法:

类级别的注解,将类映射为xml全局元素,也就是根元素。就像spring配置文件中的beans。

上面的例子中我将该注解用在了person类上,生成了根元素。常与@XmlType,@XmlAccessorType,@XmlAccessorOrder连用。

(2)属性:

该注解含有name和namespace两个属性。namespace属性用于指定生成的元素所属的命名空间。name属性用于指定生成元素的名字,若不指定则默认使用类名小写作为元素名。

修改上面的例子,在该注解上使用name属性:

@XmlRootElement(name = "human")
public class Person {
private int id;
private String name;
...
...
} //省略下面代码

生成的xml:

2、@XmlElement

(1)作用和用法:

字段,方法,参数级别的注解。该注解可以将被注解的字段(非静态),或者被注解的get/set方法对应的字段映射为本地元素,也就是子元素。默认使用字段名或get/set方法去掉前缀剩下部分小写作为元素名(在字段名和get/set方法符合命名规范的情况下)。上面例子中,id、addr、name、gender、area都被映射成了元素的子元素。下文会配合@XmlAccessorType注解详细讲解该注解的用法。常与@XmlValue,@XmlJavaTypeAdapter,@XmlElementWrapper连用。

(2)属性:

该注解的属性常用的属性有有:name、nillable、required、namespace、defaultValue

  • name属性可以指定生成元素的名字,同@XmlRootElement注解的name属性一样,不再举例。
  • nillable属性可以指定元素的文本值是否可以为空,默认为false。修改上面例子:
@XmlElement(nillable = true)
public void setName(String name) {
this.name = name;
}

则生成的xsd(为了节省篇幅,只截取必要的片段)为:

<xs:element name="name" type="xs:string" nillable="true" minOccurs="0"/>
  • required属性可以指定该元素是否必须出现,默认为false,所以在xsd中会有对应的属性minOccurs="0"。修改该属性为true
@XmlElement(nillable = true, required = true)
public void setName(String name) {
this.name = name;
}

生成的xsd文件为:

<xs:element name="name" type="xs:string" nillable="true" minOccurs="1"/>
  • namespace属性可以指定该元素所属的命名空间
  • defaultValue属性可以指定该元素默认的文本值

3、@XmlAttribute

(1)作用和用法:

字段和方法级别的注解。该注解会将字段或get/set方法对应的字段映射成本类对应元素的属性,属性名默认使用字段名或get/set方法去掉前缀剩下部分首字母小写(在字段名和get/set方法符合命名规范的情况下)。

修改上面例子:

@XmlAttribute
public void setGender(String gender) {
this.gender = gender;
}

生成的xml:



对应的xsd:

<xs:element name="human">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:string" name="addr"/>
<xs:element type="xs:string" name="area"/>
<xs:element type="xs:byte" name="id"/>
<xs:element type="xs:string" name="name"/>
</xs:sequence>
<xs:attribute type="xs:string" name="gender"/>
</xs:complexType>
</xs:element>

(2)属性:

该注解有name,required,namespace三个属性。用法和@XmlElement注解相同,不再举例,可以自己尝试下。

4、@XmlTransient

(1)作用和用法:

类,字段,方法级别的注解。可使JAXB在映射xml元素时忽略被注解的类,字段,get/set对应字段。需要注意的是该注解与所有其他JAXB注释相互排斥,也就是说与其他注释连用就会报错。

修改上面例子:

@XmlTransient
public void setId(int id) {
this.id = id;
}

生成的xml:



(2)属性:

该注解没有属性。

5、@XmlAccessorType

(1)作用和用法:

包和类级别的注解。javaEE的API对该注解的解释是:控制字段是否被默认序列化。通俗来讲,就是决定哪些字段或哪些get/set方法对应的字段会被映射为xml元素,需要注意的是字段或get/set方法的访问权限(public/private)会影响字段是否被映射为xml元素,下面会详细讲解。

(2)属性:

该注解只有一个value属性,可取的值是一个名为XmlAccessType的枚举类型里的值,下面详细看一下这几个值分别有什么用:

  • XmlAccessType.PROPERTY
  • XmlAccessType.FIELD
  • XmlAccessType.PUBLIC_MEMBER (该值为默认值)
  • XmlAccessType.NONE

6、@XmlAccessorOrder

(1)作用和用法:

包和类级别的注解。控制生成元素的顺序。

(2)属性:

只有一个value属性,可取的值是一个名为XmlAccessOrder的枚举类型的两个值,XmlAccessOrder.ALPHABETICAL 和 XmlAccessOrder.UNDEFINED。默认为XmlAccessOrder.UNDEFINED,代表按照类中字段的顺序生成元素的顺序。

另一个值则代表按照字母表的顺序对生成的元素排序。但奇怪的是,只有jaxb按照field生成元素时,默认值才会生效,否则总是按照字母表的顺序排序。

7、@XmlElementWrapper

(1)作用和用法:

字段和方法级别的注解。围绕被映射的xml元素生成包装元素。主要用在集合对象映射后生成包装映射结果的xml元素。

修改上面的例子,添加一个Key类,在Person类中添加一个Key类的Set集合,修改如下:

Key类:

@XmlRootElement
public class Key {
private String roomNum; public Key() {
} public Key(String roomNum) {
this.roomNum = roomNum;
} public String getRoomNum() {
return roomNum;
} @XmlElement
public void setRoomNum(String roomNum) {
this.roomNum = roomNum;
} @Override
public String toString() {
return "Key{" +
"roomNum='" + roomNum + '\'' +
'}';
}
}

Person类:

@XmlRootElement(name = "human")
@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
@XmlAccessorOrder(XmlAccessOrder.ALPHABETICAL)
public class Person {
...
private Set<Key> key = new HashSet<>(); public Person() {
} public Person(String name, String gender, String addr, String area) {
this.name = name;
this.gender = gender;
this.addr = addr;
this.area = area;
key.add(new Key("001")); //向集合中添加两个Key对象
key.add(new Key("002"));
}
... public Set<Key> getKey() {
return key;
} @XmlElement
public void setKey(Set<Key> key) {
this.key = key;
}
}

生成的xml:



但同一元素应该需要被“包装”一下才显得有层次感,所以可以使用@XmlElementWrapper来实现:

@XmlElementWrapper(name = "keys")
@XmlElement
public void setKey(Set<Key> key) {
this.key = key;
}

生成的xml:



(2)属性:

该注解有name、nillable、namespace、required四个属性,用法同上,不再赘述。

8、@XmlJavaTypeAdapter

(1)作用和用法:

包、类、字段,方法、参数级别的注解。解决java日期(Date),数字(Number)格式化问题。直接看例子,修改Person类,添加一个Date类型字段:

Person类:

@XmlRootElement(name = "human")
/*@XmlType(propOrder = {
"name",
"gender",
"addr",
"area"
})*/
@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
@XmlAccessorOrder(XmlAccessOrder.ALPHABETICAL)
public class Person {
...
private Date date = new Date(); ... public Date getDate() {
return date;
} @XmlElement
public void setDate(Date date) {
this.date = date;
}
}

生成的xml:

这样的date格式显然令人不满意,我们需要例如“2018-05-20”这样的格式。这就需要@XmlJavaTypeAdapter注解,自定义一个适配器来解决这个问题。该注解的用法就是自定义适配器并继承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);
}
}

Person类:

@XmlJavaTypeAdapter(DateAdapter.class)
@XmlElement
public void setDate(Date date) {
this.date = date;
}

生成的xml:

完美解决。

(2)属性:

常用的就是value属性,其他属性请自行研究。

9、@XmlValue:

(1)作用和用法:

字段和方法级别的注解。该注解的作用,简单理解就是定义xml元素文本值的类型,例如在一个类的String类型字段上使用该注解,则生成的元素文本值类型就是xsd:string,也就是定义一个xsd中的simpleType.若类中还有一个字段并使用了@XmlAttribute注解,则是定义一个xsd中的complexType。

(2)属性:

10、@XmlType:

(1)作用和用法:

类级别的注解。该注解有些复杂,主要使用的是它的propOrder属性,简单来说是用来定义xsd中的simpleType或complexType,从生成的xml中来看,它的作用就是指定生成元素的顺序,具体看下图:



简单解释下每行什么意思:

  • 若指定该注解的propOrder为{},会生成ComplexType并且使用xs:all指示器,表示所有被映射的元素都必须出现在xml中
  • 若propOrder的值为{"name", "addr", "area"}(大括号中都是Person类的字段名称),会生成ComplexType并使用xs:sequence指示器,表示生成的xml元素必须按照propOrder指定的顺序出现,也就间接实现了排序。
  • 若不指定propOrder属性(这与指定propOrder但值为{}不同),没有字段,会生成ComplexType并包含一个空的xs:sequence指示器。
  • 若不指定propOrder属性,但含有被@XmlValue注解的字段和被@XmlAttribute注解的字段,会生成一个含有simpleContent的ComplexType。
  • 若不指定propOrder属性,但含有被@XmlValue注解的字段而没有被@XmlAttribute注解的字段,会生成一个含有simpleType的ComplexType。

参考博客:

[1]JAXB常用注解讲解(超详细)

[2]XSD学习

[3]JAXB的@XmlRootElement注解

[4]WebService和xml注解

JAXB—Java类与XML文件之间转换的更多相关文章

  1. JAXB java类与xml互转

    JAXB(Java Architecture for XML Binding) 是一个业界的标准,是一项可以根据XML Schema产生Java类的技术.该过程中,JAXB也提供了将XML实例文档反向 ...

  2. 简单实体类和xml文件的相互转换

    最近写一个题目,要求将一组员工实体类转换成xml文件,或将xml文件转换成一组实体类.题目不难,但写完感觉可以利用泛型和反射将任意一个实体类和xml文件进行转换.于是今天下午立马动手 试了下,做了个简 ...

  3. JAXB注解 @XmlRootElement 及XML文件解析详解

    @Retention(value=RUNTIME) @Target(value=TYPE) public @interface XmlRootElement @Inherited @Retention ...

  4. C#对象与XMl文件之间的相互转换

    C#提供三种序列化方式,分别为: 1.是使用BinaryFormatter进行串行化: 2.使用SoapFormatter进行串行化: 3.使用XmlSerializer进行串行化.其中对于Binar ...

  5. C#对象与XMl文件之间的相互转换(转)

    本文是对C#中对象与XMl文件之间的相互转换进行了详细的介绍,需要的朋友可以过来参考下,希望对大家有所帮助 C#提供三种序列化方式,分别为:1.是使用BinaryFormatter进行串行化: 2.使 ...

  6. mybits根据表自动生成 java类和mapper 文件

    mybits根据表自动生成 java类和mapper 文件 我这个脑子啊,每次创建新的工程都会忘记是怎么集成mybits怎么生成mapper文件的,so today , I can't write t ...

  7. Java jdom解析xml文件带冒号的属性

    Java jdom解析xml文件带冒号的属性 转载请标明出处: https://dujinyang.blog.csdn.net/article/details/99644824 本文出自:[奥特曼超人 ...

  8. 简单Java类与XML之间的转换

    需要的jar包:xmlpull_1_0_5.jar,xstream-1.4.1.jar) 1.工具类XstreamUtil package com.learn.util; import com.tho ...

  9. java读取xml文件并转换成对象,并进行修改

    1.首先要写工具类,处理读取和写入xml文件使用的工具.XMLUtil.javaimport java.io.FileInputStream; import java.io.FileWriter; i ...

随机推荐

  1. 【http】https加速优化

    目录 前言 HTTPS 的连接很慢 https 步骤简要划分 握手耗时 证书验证 CRL OCSP 硬件优化 软件优化 软件升级 协议优化 证书优化 会话复用 会话票证 预共享密钥 前言 主要记录 h ...

  2. java实现rsa加密算法【5min快速应用教程】

    该篇文章的主要目的是让读者能够迅速应用到项目中,想要了解详细的rsa加密算法的,可以百度找到更多原理.深度分析的文章. RSA算法是一种非对称密码算法,所谓非对称,就是指该算法需要一对密钥,使用其中一 ...

  3. gitbook热更新时报错operation not permitted

    在使用gitbook写东西的时候,当文档内容有更新的时候,会自动更新内容到页面上,方便预览.但是,存在一个bug,就是会神奇的崩溃掉,出现如下的错误提示: Restart after change i ...

  4. C++ pragma once 与 ifndef 用法区别

    #pragma once 与 #ifndef 的作用 (1)在C/C++中,在使用预编译指令#include的时候,为了防止重复引用造成二义性. (2)在能够支持这两种方式的编译器上,二者并没有太大的 ...

  5. vm workstation pro 安装centos7

    workstation pro 下载地址 划到页面下方点击下载 安装教程 激活码 16版本 ZF3R0-FHED2-M80TY-8QYGC-NPKYF 15版本 FG78K-0UZ15-085TQ-T ...

  6. [hdu5245]Joyful

    很难考虑矩形覆盖的问题,但可以考虑每一个点被覆盖的概率/期望(把矩形分成九部分后容斥即可),sigma起来即答案 1 #include<bits/stdc++.h> 2 using nam ...

  7. Semaphore信号量的使用

    package ThreadTest; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; pub ...

  8. ServerBootstrap的handler()和childHandler()区别

    无论服务端还是客户端都进行了handler的设置,通过添加hanlder,我们可以监听Channel的各种动作以及状态的改变,包括连接,绑定,接收消息等. 区别: 1. handler在初始化时就会执 ...

  9. C#.NET 操作Windows服务(安装、卸载)

    注意点: 1.安装时要请求到管理员权限. 2.卸载前,一定要停止掉Windows服务,否则需要重启或注销电脑.代码无法停止服务时,使用services.msc来停止. 开始: 1.新建一个名为&quo ...

  10. exCRT & 骆克强乘法

    exCRT & 骆克强乘法 只是丢两个板子啦. exCRT的做法就是每次拿两个方程合并成一个,合并的过程推下式子就是个 exgcd.具体可以在 zjk 的 ptt 里面找到. 先放个 $ O( ...