JAXB常用注解讲解(超详细)
简介:
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常用注解讲解(超详细)相关推荐
- 手把手讲解超详细python入门游戏项目‘打外星飞船’(二)
手把手讲解超详细python入门游戏项目'打外星飞船'(二) 上次我们在(一)中创建了游戏的背景,现在我们这里将要实现用键盘控制飞船的移动.射击子弹,但是在此之前我们还有一个非常重要的部分–重构. 重 ...
- 手把手讲解超详细python入门游戏项目‘打外星飞船’(四)
手把手讲解超详细python入门游戏项目'打外星飞船'(四) 在经过创立屏幕.飞船移动和设置子弹,我们这里开始设置外形人的创建和移动.我们这里主要的任务是:创建一众外星人让它们充满屏幕,让他们向下和两 ...
- 手把手讲解超详细python入门游戏项目‘打外星飞船’(五)
手把手讲解超详细python入门游戏项目'打外星飞船'(五) 这是最后一个项目了,前面我们讲了整个游戏页面的控制.飞船.子弹.外星人的创建,这里我们讨论一下子弹射杀外星人和整个游戏的结束,我们这里的文 ...
- 手把手讲解超详细python入门游戏项目‘打外星飞船’(三)
手把手讲解超详细python入门游戏项目'打外星飞船'(三) 第三部分我们讲解一下飞船需要射出子弹,那么子弹的部分是怎么操作呢?接下来我直接把项目的四个文件展示出来,以注释的形式在旁边讲解.因为有很多 ...
- 手把手讲解超详细python入门游戏项目‘打外星飞船’(一)
手讲解超详细python入门游戏项目'打外星飞船'手把(一) 由于内容比较多,这里会分为五篇文章来讲解,从页面的创建.飞船控制.射击.外星人创建.射杀外星人五片来展开. 做一个窗口和设置响应用户 im ...
- SVN服务器安装与常用操作(超详细)
SVN服务器安装与常用操作(超详细) 服务器 1.下载SVN服务器,地址:http://subversion.apache.org/packages.html 进入网址后,滚动到浏览器最底部看到如下截 ...
- Nginx实战部署常用功能演示(超详细版),绝对给力~~~
前言 上次分享了一些开发过程中常用的功能,但如果到真实环境中,其实还需要一些额外的配置,比如说跨域.缓存.配置SSL证书.高可用等,老规矩,还是挑几个平时比较常用的进行演示分享.上篇详见Nginx超详 ...
- 适合小白的Linux入门学习教程,从安装到实操(涵盖各种常用指令,超详细!)
Linux入门学习 Linux简介 Linux是什么 Linux的特点 Linux和Windows的区别 Linux入门 我们为什么要学习Linux 环境搭建 安装CentOS 购买云服务器 走进Li ...
- 广搜(bfs)模板太好用了!bfs详细讲解--超详细题目分析(持续更新题目----)【算法分享】
广搜讲解目录 广搜回顾 广搜题目 noj1541八数码问题 题目描述: 题目要求即样例 题目分析 题解代码[注解详细]---理解BFS noj1652 僵尸来了 题目描述 题目要求及样例 题目分析 题 ...
最新文章
- vim的基本快捷操作(二)——可视模式
- Leetcode: Remove Element
- linux--gdb调试
- 45 张图深度解析 Netty 架构与原理
- CentOS7安装mysql8并配置
- (转)RabbitMQ学习之集群部署
- BSD socket编程学习
- 一步一步学习Servlet中Request和Response
- Miniflter中 NPInstanceSetup调查
- 线程同步之条件变量和信号量(生产者消费者模型)
- 【超全汇总】学习数据结构与算法,计算机基础知识,看这篇就够了
- 看服务器硬盘序列号,获得服务器硬件信息(CPUID、硬盘号、主板序列号、IP地址等)...
- java基于springboot校园音乐点歌网站平台ssm
- Java 学习 多态练习 1. 设计一个接口 接口叫做Mortal,其中有一个方法叫做die 在主方法中首先实例化出一个Hero对象:盖伦然后实例化出3个对象,分别是ADHero,APHero
- Word怎么快速插入空白页
- Win11后续更新计划:微软将逐步取消传统的控制面板功能
- 解密最近几年的新型骗局-情侣网店、未交易、淘宝内部券,你中招了几个
- 手机投屏不是全屏怎么办_手机投屏win10怎么退出全屏详细图文教程
- HTTP错误 404.17 - Not Found IIS 7.5 请求的内容似乎是脚本,因而将无法由静态文件处理程序来处理
- bugly热更新、多渠道集成及加固问题
热门文章
- php ip 库,php使用GeoIP库实例
- Linux ping6 本地ipv6地址(local ipv6 address) 无效的参数(Invalid argument)
- LabVIEW问题解决——“运行前面板小于最小化前面板,这将导致VI无法正常工作”。
- 典型相关分析,奇异值分解,RRR(Reduced-Rank Regression)
- webmagic mysql_webmagic使用
- FastClick插件
- 树莓派linux桌面分辨率,树莓派3B+ Raspbian桌面分辨率设置
- 冒泡法排序(PTA)
- python3.10安装环境搭建,以及出现安装python出现0x80070643问题解决,
- 2021Java高级面试题及答案,太牛了!