使用XStream是实现XML与Java对象的转换(3)--注解
六、使用注解(Annotation)
总是使用XStream对象的别名方法和注册转换器,会让人感到非常的乏味,又会产生很多重复性代码,于是我们可以使用注解的方式来配置要序列化的POJO对象。
1,最基本的注解:类的别名性注解和字段的别名性注解(XStreamAlias)
有这样一段代码:
- import com.thoughtworks.xstream.XStream;
- public class XStreamTest3 {
- public static void main(String[] args) {
- XStream stream = new XStream();
- RendezvousMessage msg = new RendezvousMessage(15);
- System.out.println(stream.toXML(msg));
- }
- }
- class RendezvousMessage {
- private int messageType;
- public RendezvousMessage(int messageType) {
- this.messageType = messageType;
- }
- }
运行结果是:
- <cn.tjpu.zhw.xml.RendezvousMessage>
- <messageType>15</messageType>
- </cn.tjpu.zhw.xml.RendezvousMessage>
如果我们需要将输出的XML文本是这样:
- <message>
- <type>15</type>
- </message>
该怎么办?
我们当然可以在main方法中调用XStream对象的别名映射方法进行处理,但我们也可以使用更简单的注解的方式进行处理。
对RendezvousMessage类的定义进行注解如下:
- //对类的别名性注解
- @XStreamAlias("message")
- class RendezvousMessage {
- //对字段的别名性注解
- @XStreamAlias("type")
- private int messageType;
- public RendezvousMessage(int messageType) {
- this.messageType = messageType;
- }
- }
但是,我们进行注解之后发现输出的结果并没有改变,为什么?
因为XStream对象默认是不读取和识别注解的,需要我们主动提醒它,而后XStream对象才能在转换的的时候读取注解。
更改main方法如下:
- public static void main(String[] args) {
- XStream stream = new XStream();
- //通知XStream对象读取并识别RendezvousMessage中的注解
- stream.processAnnotations(RendezvousMessage.class);
- RendezvousMessage msg = new RendezvousMessage(15);
- System.out.println(stream.toXML(msg));
- }
这样输出的结果就能与预想的一样了。
注意:当使用XStream对象处理一个被注解的类型时,XStream对象也会处理所有与其相关的类型的注解信息,即该类型的父类、父接口、所有子类的注解。
processAnnotations方法还有一个重载的方法,是以Class []作为参数的。
2,隐式集合注解(XStreamImplicit)
现在我们给RendezvousMessage类添加一个List集合字段,并且更改一下RendezvousMessage的构造方法,新的代码如下:
- import java.util.Arrays;
- import java.util.List;
- import com.thoughtworks.xstream.XStream;
- import com.thoughtworks.xstream.annotations.XStreamAlias;
- public class XStreamTest3 {
- public static void main(String[] args) {
- XStream stream = new XStream();
- //通知XStream对象读取并识别RendezvousMessage中的注解
- stream.processAnnotations(RendezvousMessage.class);
- RendezvousMessage msg = new RendezvousMessage(15,"first","second");
- System.out.println(stream.toXML(msg));
- }
- }
- //对类的别名性注解
- @XStreamAlias("message")
- class RendezvousMessage {
- //对字段的别名性注解
- @XStreamAlias("type")
- private int messageType;
- //新添加的集合字段
- private List<String> content;
- //经改造的构造方法
- public RendezvousMessage(int messageType, String ... content) {
- this.messageType = messageType;
- this.content = Arrays.asList(content);
- }
- }
运输出结果如下:
- <message>
- <type>15</type>
- <content class="java.util.Arrays$ArrayList">
- <a class="string-array">
- <string>first</string>
- <string>second</string>
- </a>
- </content>
- </message>
但是,如果我们想让输出的XML格式如下:
- <message>
- <type>15</type>
- <part>firstPart</part>
- <part>secondPart</part>
- </message>
该怎么办?
现在我们给集合字段添加隐式集合性注解,以去除集合的根节点:
- //对类的别名性注解
- @XStreamAlias("message")
- class RendezvousMessage {
- //对字段的别名性注解
- @XStreamAlias("type")
- private int messageType;
- //隐式集合性注解
- @XStreamImplicit
- private List<String> content;
- public RendezvousMessage(int messageType, String ... content) {
- this.messageType = messageType;
- this.content = Arrays.asList(content);
- }
- }
重新运行程序,输出结果如下:
- <message>
- <type>15</type>
- <string>first</string>
- <string>second</string>
- </message>
输出的结果中,集合的每一个子节点的节点名都是string,现在需要将子节点的节点名改为part,这样就需要继续更改注解项:
- //对类的别名性注解
- @XStreamAlias("message")
- class RendezvousMessage {
- //对字段的别名性注解
- @XStreamAlias("type")
- private int messageType;
- //对隐式集合的注解,将每一个子节点的节点名都改为part
- @XStreamImplicit(itemFieldName="part")
- private List<String> content;
- public RendezvousMessage(int messageType, String ... content) {
- this.messageType = messageType;
- this.content = Arrays.asList(content);
- }
- }
这样输出的结果就能够跟预想的一样了,成功了!!!
注意:隐式集合注解同样可以用于数组和Map对象。
3,注解转换器(XStreamConverter)
现在我们再给RendezvousMessage类添加两个字段,一个boolean字段和一个时间Calendar字段,代码如下:
- public class XStreamTest3 {
- public static void main(String[] args) {
- XStream stream = new XStream();
- // 通知XStream对象读取并识别RendezvousMessage中的注解
- stream.processAnnotations(RendezvousMessage.class);
- RendezvousMessage msg = new RendezvousMessage(15,false,"first","second");
- System.out.println(stream.toXML(msg));
- }
- }
- // 对类的别名性注解
- @XStreamAlias("message")
- class RendezvousMessage {
- // 对字段的别名性注解
- @XStreamAlias("type")
- private int messageType;
- // 隐式集合性注解
- @XStreamImplicit(itemFieldName = "part")
- private List<String> content;
- private boolean important;
- private Calendar created = new GregorianCalendar();
- // 再次对构造方法进行了改造
- public RendezvousMessage(int messageType, boolean important,
- String... content) {
- this.messageType = messageType;
- this.important = important;
- this.content = Arrays.asList(content);
- }
- }
运行结果如下:
- <message>
- <type>15</type>
- <part>first</part>
- <part>second</part>
- <important>false</important>
- <created>
- <time>1387534087343</time>
- <timezone>Asia/Shanghai</timezone>
- </created>
- </message>
现在,我们要将输出结果改造为:
- <message>
- <type>15</type>
- <part>firstPart</part>
- <part>secondPart</part>
- <important>no</important>
- <created>1379430873703</created>
- </message>
该如何做?
首先,我们使用注解处理Calendar时间字段的转换,先定义一个时间的转换器SingleValueCalendarConverter,代码如下:
- package cn.tjpu.zhw.xml;
- import java.util.Calendar;
- import java.util.Date;
- import java.util.GregorianCalendar;
- import com.thoughtworks.xstream.converters.Converter;
- import com.thoughtworks.xstream.converters.MarshallingContext;
- import com.thoughtworks.xstream.converters.UnmarshallingContext;
- import com.thoughtworks.xstream.io.HierarchicalStreamReader;
- import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
- //必须是public类型
- public class SingleValueCalendarConverter implements Converter {
- public void marshal(Object source, HierarchicalStreamWriter writer,
- MarshallingContext context) {
- Calendar calendar = (Calendar) source;
- writer.setValue(String.valueOf(calendar.getTime().getTime()));
- }
- public Object unmarshal(HierarchicalStreamReader reader,
- UnmarshallingContext context) {
- GregorianCalendar calendar = new GregorianCalendar();
- calendar.setTime(new Date(Long.parseLong(reader.getValue())));
- return calendar;
- }
- public boolean canConvert(Class type) {
- return type.equals(GregorianCalendar.class);
- }
- }
然后,我们需要使用SingleValueCalendarConverter转换器对Calendar字段进行注解:
- //对类的别名性注解
- @XStreamAlias("message")
- class RendezvousMessage {
- //对字段的别名性注解
- @XStreamAlias("type")
- private int messageType;
- //对隐式集合的注解,将每一个子节点的节点名都改为part
- @XStreamImplicit(itemFieldName="part")
- private List<String> content;
- private boolean important;
- //为该字段的注解指定转换器
- @XStreamConverter(SingleValueCalendarConverter.class)
- private Calendar created = new GregorianCalendar();
- public RendezvousMessage(int messageType, String ... content) {
- this.messageType = messageType;
- this.content = Arrays.asList(content);
- }
- }
运行结果如下:
- <message>
- <type>15</type>
- <part>first</part>
- <part>second</part>
- <important>false</important>
- <created>1387534774062</created>
- </message>
但是我们发现important节点中的内容是true或false,怎样让它变成yes或no呢?
我们可以使用框架为我们提供的一个转换器BooleanConverter
修改RendezvousMessage的类定义:
- //对类别名的注解
- @XStreamAlias("message")
- class RendezvousMessage {
- //对字段别名的注解
- @XStreamAlias("type")
- private int messageType;
- //对隐式集合的注解,将每一个子节点的节点名都改为part
- @XStreamImplicit(itemFieldName="part")
- private List<String> content;
- //将true/false改为yes/no
- @XStreamConverter(value=BooleanConverter.class, booleans={false}, strings={"yes", "no"})
- private boolean important;
- //为该字段添加转换器注解
- @XStreamConverter(SingleValueCalendarConverter.class)
- private Calendar created = new GregorianCalendar();
- public RendezvousMessage(int messageType, boolean important, String... content) {
- this.messageType = messageType;
- this.important = important;
- this.content = Arrays.asList(content);
- }
- }
运行结果如下:
- <message>
- <type>15</type>
- <part>first</part>
- <part>second</part>
- <important>no</important>
- <created>1387534827609</created>
- </message>
这正是我们想要的!!!!
4,属性注解
现在我们想将上面的XML格式改造成为:
- <message type="15" important="no">
- <part>firstPart</part>
- <part>secondPart</part>
- <created>1154097812245</created>
- </message>
,也就是把type节点和important节点作为父节点的属性,该怎么做?
答案是,使用属性注解:
@XStreamAsAttribute
代码如下:
- public class XStreamTest3 {
- public static void main(String[] args) {
- XStream stream = new XStream();
- // 通知XStream对象读取并识别RendezvousMessage中的注解
- stream.processAnnotations(RendezvousMessage.class);
- RendezvousMessage msg = new RendezvousMessage(15, false, "first",
- "second");
- System.out.println(stream.toXML(msg));
- }
- }
- // 对类的别名性注解
- @XStreamAlias("message")
- class RendezvousMessage {
- //将type节点变成属性
- @XStreamAsAttribute
- // 对字段的别名性注解
- @XStreamAlias("type")
- private int messageType;
- // 隐式集合性注解
- @XStreamImplicit(itemFieldName = "part")
- private List<String> content;
- //将important节点变成属性
- @XStreamAsAttribute
- // 将true/false改为yes/no
- @XStreamConverter(value = BooleanConverter.class, booleans = { false }, strings = {
- "yes", "no" })
- private boolean important;
- @XStreamConverter(SingleValueCalendarConverter.class)
- private Calendar created = new GregorianCalendar();
- public RendezvousMessage(int messageType, boolean important,
- String... content) {
- this.messageType = messageType;
- this.important = important;
- this.content = Arrays.asList(content);
- }
- }
结果是:
- <message type="15" important="no">
- <part>first</part>
- <part>second</part>
- <created>1387540760390</created>
- </message>
我们有成功了!!!!
5,使用注解将字段转换为父节点文本内容
我们如果想得到的XML是如下形式:
- <message type="15" important="no" created="1154097812245">This is the message content.</message>
就是将type、important、created三个节点全部变属性,并且将content节点的内容变为父节点message的内容,如何做?
这就需要用到
ToAttributedValueConverter转换器注解
代码如下:
- // 新加的转换器注解
- @XStreamConverter(value = ToAttributedValueConverter.class, strings = { "content" })
- // 对类的别名性注解
- @XStreamAlias("message")
- class RendezvousMessage {
- // 将type节点变成属性
- @XStreamAsAttribute
- // 对字段的别名性注解
- @XStreamAlias("type")
- private int messageType;
- // 隐式集合性注解
- @XStreamImplicit(itemFieldName = "part")
- private List<String> content;
- // 将important节点变成属性
- @XStreamAsAttribute
- // 将true/false改为yes/no
- @XStreamConverter(value = BooleanConverter.class, booleans = { false }, strings = {
- "yes", "no" })
- private boolean important;
- @XStreamConverter(SingleValueCalendarConverter.class)
- private Calendar created = new GregorianCalendar();
- public RendezvousMessage(int messageType, boolean important,
- String... content) {
- this.messageType = messageType;
- this.important = important;
- this.content = Arrays.asList(content);
- }
- }
但是运行之后,会发现,运行结果根本与我们预期的不一样,为什么?
因为ToAttributedValueConverter转换器接受的content节点必须是String类型或者有一个转换器将content装换为String类型!!!
例如,将content节点变为String类型:
- //新加的转换注解
- @XStreamConverter(value = ToAttributedValueConverter.class, strings = { "content" })
- //对类的别名性注解
- @XStreamAlias("message")
- class RendezvousMessage {
- // 对字段的别名性注解
- @XStreamAlias("type")
- private int messageType;
- //由原来的List<String>类型变为String类型
- private String content;
- // 将true/false改为yes/no
- @XStreamConverter(value = BooleanConverter.class, booleans = { false }, strings = {
- "yes", "no" })
- private boolean important;
- // @XStreamConverter(SingleValueCalendarConverter.class)
- // private Calendar created = new GregorianCalendar();
- // 再次对构造方法进行了改造
- public RendezvousMessage(int messageType, boolean important,
- String content) {
- this.messageType = messageType;
- this.important = important;
- this.content = content;
- }
- }
运行结果为:
- <message type="15" important="no">这是一大串content节点的内容</message>
虽然type和important节点没有使用@XStreamAsAttribute注解,但是却被隐式的转换为属性。
6,使用注解忽略某些字段
忽略messageType字段可以使用@XStreamOmitField注解
代码如下:
- //对类的别名性注解
- @XStreamAlias("message")
- class RendezvousMessage {
- //忽略messageType字段
- @XStreamOmitField
- // 将type节点变成属性
- @XStreamAsAttribute
- // 对字段的别名性注解
- @XStreamAlias("type")
- private int messageType;
- // 隐式集合性注解
- @XStreamImplicit(itemFieldName = "part")
- private List<String> content;
- // 将important节点变成属性
- @XStreamAsAttribute
- // 将true/false改为yes/no
- @XStreamConverter(value = BooleanConverter.class, booleans = { false }, strings = {
- "yes", "no" })
- private boolean important;
- @XStreamConverter(SingleValueCalendarConverter.class)
- private Calendar created = new GregorianCalendar();
- // 再次对构造方法进行了改造
- public RendezvousMessage(int messageType, boolean important,
- String... content) {
- this.messageType = messageType;
- this.important = important;
- this.content = Arrays.asList(content);
- }
- }
运行结果:
- <message important="no">
- <part>first</part>
- <part>second</part>
- <created>1387544212500</created>
- </message>
7,自动检测注解
之前我们启用某个类的注解时,都需要使用processAnnotations方法通知xstream对象解析注解类,其实我们还有一个更简便的模式,即调用autodetectAnnotations(true)方法,让xstream对象自动检测注解类:
- public class XStreamTest3 {
- public static void main(String[] args) {
- XStream stream = new XStream();
- // // 通知XStream对象读取并识别RendezvousMessage中的注解
- // stream.processAnnotations(RendezvousMessage.class);
- //自动检测注解
- stream.autodetectAnnotations(true);
- RendezvousMessage msg = new RendezvousMessage(15, false, "first","second");
- System.out.println(stream.toXML(msg));
- }
- }
注意:1,自动检测注解模式,会使XStream的解析变慢!2,在任何地方调用processAnnotations方法之后,自动检测注解模式将会被关闭。
使用XStream是实现XML与Java对象的转换(3)--注解的更多相关文章
- 使用XStream是实现XML与Java对象的转换(6)--持久化
九.持久化 在第八节的示例中,当我们操作一组对象时,我们可以指定Writer.OutputStream来写出序列化后的XML数据,我们还可以指定Reader.InputStream来读取序列化后的XM ...
- 使用XStream是实现XML与Java对象的转换(4)--转换器
七.转换器(Converter) 我们程序中的POJO是千变万化的,而且需求也是千奇百怪的,所以XStream中的内置的转换器的功能不一定能够满足我们的要求,所以我们就需要自己构建转换器. 1,一个基 ...
- 使用XStream是实现XML与Java对象的转换(1)--简介及入门示例
一.简单介绍 XStream是thoughtworks开发的开源框架,用于实现XML数据于Java对象.Json数据的转换.它不需要schema或其他的mapping文件就可以进行java对象和xml ...
- 使用XStream是实现XML与Java对象的转换(5)--Object Stream
八,Object Stream 之前的例子我们都是直接输出Xml成为String类型或者从String中获得并解析Xml,现在我们要处理输入流和输出流! 1,输出流(ObjectOutputStrea ...
- 使用XStream是实现XML与Java对象的转换(2)--别名
五.使用别名(Alias) 首先,有这样一段Java代码: import java.util.ArrayList; import java.util.List; import com.thoughtw ...
- 不规矩的xml与JAVA对象互相转换的小技巧-使用Marshaller
摘要:将XML文档与JAVA对象互转是很常见的需求,如果XML定义很规整这很好实现.然而在现实中“不规矩”的XML可能更常见,Marshaller便无能为力了吗?下面是一个小技巧,调整一下思维便能重用 ...
- XStream轻松转换xml和java对象
首先引入所需的jar: xstream-1.4.9.xpp3_min-1.1.4c.dom4j-1.6.1, 或用maven管理jar包时在pom.xml中添加: <!-- https://mv ...
- xml-mapping xml 与 java 对象转换映射框架,像 XStream 一样优雅地读写xml
xml xml 是 java 实现的 xml 框架. 希望以最优雅的方式进行 xml 和 java 之间的转换处理,一行代码搞定一切. 特点 对象的和 xml 的互相映射 支持注解 @Alias 指定 ...
- XML 和 java对象相互转换
XML 和 java对象相互转换 博客分类: XML 和 JSON 下面使用的是JDK自带的类,没有引用任何第三方jar包. Unmarshaller 类使客户端应用程序能够将 XML 数据转换为 ...
随机推荐
- 6.4、Android Studio的GPU Monitor
Android Monitor包含GPU Monitor,它将可视化的显示渲染窗体的时间.GPU Monitor可以帮助你: 1. 迅速查看UI窗体生成 2. 辨别是否渲染管道超出使用线程时间 在GP ...
- Android ListPopupWindow的使用
其实像ListPopupWindow.PopupMenu的用法大致和PopupWindow的一样!就不讲了,相信用过PopupWindow的看一下就能明白. 先上个效果图: ListPopupWind ...
- 浅谈C语言 extern 指针与数组
/* * d.c * * Created on: Nov 15, 2011 * Author: root */ #include "apue.h" int a[] = {3,2}; ...
- 【如何快速的开发一个简单的iOS直播app】(代码篇)
开篇([如何快速的开发一个完整的iOS直播app](原理篇)) 好久没写简书,因为好奇的我跑去学习直播了,今天就分享一下我的感慨. 目前为止直播还是比较热点的技术的,简书,git上有几篇阅读量和含金量 ...
- Socket编程实践(13) --UNIX域协议
UNIX域协议 UNIX域套接字与TCP相比, 在同一台主机上, UNIX域套接字更有效率, 几乎是TCP的两倍(由于UNIX域套接字不需要经过网络协议栈,不需要打包/拆包,计算校验和,维护序号和应答 ...
- JUI/DWZ 分页 Servlet
分页介绍 参考:官方用户手册中的"分页组件" 分页思路服务器返回当前页的数据,总条数,再由js来生成分页标签.分页是配合服务器端来处理的, 不是存js做的分页. 因 ...
- Device Tree Usage(理解DTS文件语法)
Basic Data Format The device tree is a simple tree structure of nodes and properties. Properties are ...
- awk 循环语句例子
awk 循环语句例子 运行结果:
- OC内存管理-OC笔记
内存管理细节:http://blog.sina.com.cn/s/blog_814ecfa90102vus2.html 学习目标 1.[理解]内存管理 2.[掌握]第一个MRC程序 3.[掌握]内存管 ...
- 限制UITextField的输入字数(长度)最正确的方法
在开发中, 有些时候会碰到这样的需求: 希望输入框有最大字数限制. 比如, 用户昵称长度限制, 评论最大字数限制.所以通过相关测试和浏览文章,使用下面的方法可以基本解决问题. 在viewDidLoad ...