简介:

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

一个简单的例子

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;}@XmlElementpublic void setId(int id) {this.id = id;}public String getName() {return name;}@XmlElementpublic void setName(String name) {this.name = name;}public String getGender() {return gender;}@XmlElementpublic void setGender(String gender) {this.gender = gender;}public String getAddr() {return addr;}@XmlElementpublic void setAddr(String addr) {this.addr = addr;}public String getArea() {return area;}@XmlElementpublic void setArea(String area) {this.area = area;}@Overridepublic String toString() {return "Person{" +"id=" + id +", name='" + name + '\'' +", gender='" + gender + '\'' +", addr='" + addr + '\'' +", area='" + area + '\'' +'}';}
}

Test:

public class JAXBTest {@Testpublic 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编组(转换)为xmlMarshaller 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();}}@Testpublic 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():

是不是很方便?这只是一个最简单的小例子,下文会在这个例子的基础上介绍和讲解其他的一些常用JAXB注解。因为会使用到部分xsd的知识,不了解的读者可以看我另一篇博客:《xsd学习:超详细解析》,否则下文会有些理解困难。

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

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

直接使用默认的配置,已经足够应付大多数情况,读者可以试一下。

常用注解:

@XmlRootElement:

作用和用法:

类级别的注解,将类映射为xml全局元素,也就是根元素。就像spring配置文件中的beans。上面的例子中我将该注解用在了person类上,生成了<person>根元素。常与@XmlType,@XmlAccessorType,@XmlAccessorOrder连用。

属性:

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

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

生成的xml:

@XmlElement

作用和用法:

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

属性:

该注解的属性常用的属性有有: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属性可以指定该元素默认的文本值


@XmlAttribute

作用和用法:

字段和方法级别的注解。该注解会将字段或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>

属性:

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

@XmlTransient

作用和用法:

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

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

生成的xml:

属性:

该注解没有属性。

@XmlAccessorType

作用和用法:

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

属性:

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

XmlAccessType.PROPERTY:

官方解释:

Every getter/setter pair in a JAXB-bound class will be automatically bound to XML, unless annotated by {@link XmlTransient}.
jaxb绑定类中的每个getter/setter对都将自动绑定到XML,除非用@XmlTransient注释。
Fields are bound to XML only when they are explicitly annotated by some of the JAXB annotations.
只有在某些JAXB注释显式地注释字段时,字段才被绑定到XML。

补充:

1.当使用了该值,只要字段有对应的get/set方法对(注意是成对出现,只有其中一个不会发生映射),不需要使用@XmlElement注解,不论该方法的访问权限是什么(即使是private),jaxb就会将该字段映射成xml元素。不过最好加上@XmlElement注解,get/set方法任选一个即可,都加上会报错。

2.若在一个字段有set/get方法对但又在字段上添加@XmlElement注解会报属性重复的错误。

3.若没有set/get方法对,则需要在字段上使用@XmlElement注解才可以映射为xml元素,否则不会发生映射。

4.若get/set方法上使用了@XmlTransient注解,但想要对应字段发生映射,需要在对应字段上添加@XmlElement注解,此时不会报错,并将该字段映射为xml元素。

XmlAccessType.FIELD:

官方解释:

Every non static, non transient field in a JAXB-bound class will be automatically bound to XML, unless annotated by {@link XmlTransient}.
jaxb绑定类中的每个非静态、非瞬态字段都将自动绑定到XML,除非使用@XmlTransient进行注释。
Getter/setter pairs are bound to XML only when they are explicitly annotated by some of the JAXB annotations.
只有当某些JAXB注释显式地对getter/setter对进行注释时,它们才会绑定到XML。

补充:

1.每个非静态的字段(无论访问权限如何)都会被jaxb映射为xml元素,即使没有get/set方法对,即使没有使用@XmlElement元素,但最好加上该注解以表明该字段要被映射为xml元素。

2.虽然没有get/set方法对,也会发生映射,但加上get/set方法对也不会报错,因为我们经常会使用这两个方法。但注意,不能再在这两个方法上使用@XmlElement方法,否则会报属性重复的错误。

3.若在字段上使用了@XmlTransient注解,但还想让该字段发生映射,需要在该字段对应的get/set方法上添加@XmlElement

XmlAccessType.PUBLIC_MEMBER (该值为默认值):

官方解释:

Every public getter/setter pair and every public field will be automatically bound to XML, unless annotated by {@link XmlTransient}.
每个公共getter/setter对和每个公共字段都将自动绑定到XML,除非使用@XmlTransient注释。
Fields or getter/setter pairs that are private, protected, or defaulted to package-only access are bound to XML only when they areexplicitly annotated by the appropriate JAXB annotations.
只有在适当的JAXB注释显式地注释了字段或getter/setter对之后,才会将它们绑定到XML。

补充:

1.每个访问权限为public的字段,或者每个访问权限为public的get/set方法对,都会将字段映射为xml元素,即使不使用@XmlElement,但最好加上。不可同时存在public字段和对应的get/set方法对,不然会报属性重复的错误。

2.若使用@XmlElement注解,需要注意只能在字段或get/set方法添加,两者任选其一,否则会报属性重复的错误。

3.若字段不为public,get/set方法为public并使用了@XmlTransient,需要在字段上添加@XmlElement才会发生映射。

若字段为public并使用了@XmlTransient,get/set方法对不为public,需要在get/set方法上使用@XmlElement才会映射。

XmlAccessType.NONE:

官方解释:

None of the fields or properties is bound to XML unless they are specifically  annotated with some of the JAXB annotations.
任何字段或属性都不会绑定到XML,除非使用某些JAXB注释对它们进行特别注释。

补充:

任何字段,get/set方法对都不会发生映射,除非使用某些注解,如@XmlElement,@XmlElementWrapper等。


@XmlAccessorOrder

作用和用法:

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

属性:

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

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

@XmlElementWrapper

作用和用法:

字段和方法级别的注解。围绕被映射的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;}@XmlElementpublic void setRoomNum(String roomNum) {this.roomNum = roomNum;}@Overridepublic 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;}@XmlElementpublic void setKey(Set<Key> key) {this.key = key;}
}

生成的xml:

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

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

生成的xml:

这样是不是好多了?

属性:

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


@XmlJavaTypeAdapter

作用和用法:

包、类、字段,方法、参数级别的注解。解决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;}@XmlElementpublic 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");@Overridepublic Date unmarshal(String date) throws Exception {return SDF.parse(date);}@Overridepublic String marshal(Date date) throws Exception {return SDF.format(date);}
}

Person类:

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

生成的xml:

完美解决。

属性:

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

@XmlValue:

作用和用法:

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

属性:

@XmlType:

作用和用法:

类级别的注解。该注解有些复杂,主要使用的是它的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。

再次强调,如果以上解释看不懂,先学xsd。传送门:《XSD学习》


JAXB常用注解讲解(超详细)相关推荐

  1. 手把手讲解超详细python入门游戏项目‘打外星飞船’(二)

    手把手讲解超详细python入门游戏项目'打外星飞船'(二) 上次我们在(一)中创建了游戏的背景,现在我们这里将要实现用键盘控制飞船的移动.射击子弹,但是在此之前我们还有一个非常重要的部分–重构. 重 ...

  2. 手把手讲解超详细python入门游戏项目‘打外星飞船’(四)

    手把手讲解超详细python入门游戏项目'打外星飞船'(四) 在经过创立屏幕.飞船移动和设置子弹,我们这里开始设置外形人的创建和移动.我们这里主要的任务是:创建一众外星人让它们充满屏幕,让他们向下和两 ...

  3. 手把手讲解超详细python入门游戏项目‘打外星飞船’(五)

    手把手讲解超详细python入门游戏项目'打外星飞船'(五) 这是最后一个项目了,前面我们讲了整个游戏页面的控制.飞船.子弹.外星人的创建,这里我们讨论一下子弹射杀外星人和整个游戏的结束,我们这里的文 ...

  4. 手把手讲解超详细python入门游戏项目‘打外星飞船’(三)

    手把手讲解超详细python入门游戏项目'打外星飞船'(三) 第三部分我们讲解一下飞船需要射出子弹,那么子弹的部分是怎么操作呢?接下来我直接把项目的四个文件展示出来,以注释的形式在旁边讲解.因为有很多 ...

  5. 手把手讲解超详细python入门游戏项目‘打外星飞船’(一)

    手讲解超详细python入门游戏项目'打外星飞船'手把(一) 由于内容比较多,这里会分为五篇文章来讲解,从页面的创建.飞船控制.射击.外星人创建.射杀外星人五片来展开. 做一个窗口和设置响应用户 im ...

  6. SVN服务器安装与常用操作(超详细)

    SVN服务器安装与常用操作(超详细) 服务器 1.下载SVN服务器,地址:http://subversion.apache.org/packages.html 进入网址后,滚动到浏览器最底部看到如下截 ...

  7. Nginx实战部署常用功能演示(超详细版),绝对给力~~~

    前言 上次分享了一些开发过程中常用的功能,但如果到真实环境中,其实还需要一些额外的配置,比如说跨域.缓存.配置SSL证书.高可用等,老规矩,还是挑几个平时比较常用的进行演示分享.上篇详见Nginx超详 ...

  8. 适合小白的Linux入门学习教程,从安装到实操(涵盖各种常用指令,超详细!)

    Linux入门学习 Linux简介 Linux是什么 Linux的特点 Linux和Windows的区别 Linux入门 我们为什么要学习Linux 环境搭建 安装CentOS 购买云服务器 走进Li ...

  9. 广搜(bfs)模板太好用了!bfs详细讲解--超详细题目分析(持续更新题目----)【算法分享】

    广搜讲解目录 广搜回顾 广搜题目 noj1541八数码问题 题目描述: 题目要求即样例 题目分析 题解代码[注解详细]---理解BFS noj1652 僵尸来了 题目描述 题目要求及样例 题目分析 题 ...

最新文章

  1. vim的基本快捷操作(二)——可视模式
  2. Leetcode: Remove Element
  3. linux--gdb调试
  4. 45 张图深度解析 Netty 架构与原理
  5. CentOS7安装mysql8并配置
  6. (转)RabbitMQ学习之集群部署
  7. BSD socket编程学习
  8. 一步一步学习Servlet中Request和Response
  9. Miniflter中 NPInstanceSetup调查
  10. 线程同步之条件变量和信号量(生产者消费者模型)
  11. 【超全汇总】学习数据结构与算法,计算机基础知识,看这篇就够了
  12. 看服务器硬盘序列号,获得服务器硬件信息(CPUID、硬盘号、主板序列号、IP地址等)...
  13. java基于springboot校园音乐点歌网站平台ssm
  14. Java 学习 多态练习 1. 设计一个接口 接口叫做Mortal,其中有一个方法叫做die 在主方法中首先实例化出一个Hero对象:盖伦然后实例化出3个对象,分别是ADHero,APHero
  15. Word怎么快速插入空白页
  16. Win11后续更新计划:微软将逐步取消传统的控制面板功能
  17. 解密最近几年的新型骗局-情侣网店、未交易、淘宝内部券,你中招了几个
  18. 手机投屏不是全屏怎么办_手机投屏win10怎么退出全屏详细图文教程
  19. HTTP错误 404.17 - Not Found IIS 7.5 请求的内容似乎是脚本,因而将无法由静态文件处理程序来处理
  20. bugly热更新、多渠道集成及加固问题

热门文章

  1. php ip 库,php使用GeoIP库实例
  2. Linux ping6 本地ipv6地址(local ipv6 address) 无效的参数(Invalid argument)
  3. LabVIEW问题解决——“运行前面板小于最小化前面板,这将导致VI无法正常工作”。
  4. 典型相关分析,奇异值分解,RRR(Reduced-Rank Regression)
  5. webmagic mysql_webmagic使用
  6. FastClick插件
  7. 树莓派linux桌面分辨率,树莓派3B+ Raspbian桌面分辨率设置
  8. 冒泡法排序(PTA)
  9. python3.10安装环境搭建,以及出现安装python出现0x80070643问题解决,
  10. 2021Java高级面试题及答案,太牛了!