概述
我们在开发的过程中,有的时候需要转换一些自定义类型,此时默认的映射方式可能无法满足需要。
XStream为我们提供了丰富的扩展,用户可以实现自己的转换器,然后调用registerConverter方法注册自定义的转换器。
实现自定义的转换器很简单,只需要实现XStream提供的Converter接口并实现其方法即可。
示例
我们在上个案例中的代码
package com.xgj.oxm.xstream.quickDemo.convert; import java.text.ParseException; import java.util.Date; import java.util.Locale; import com.thoughtworks.xstream.XStream; import com.xgj.oxm.xstream.quickDemo.domain.LoginLog; import com.xgj.oxm.xstream.quickDemo.domain.User; public class XStreamConverterDemo { private static XStream xstream; static { // 创建一个Xstream实例,使用默认的XPP解析器 xstream = new XStream(); // (1)设置类别名,修改默认的全限定名的名称 xstream.alias("user", User.class); xstream.alias("loginLog", LoginLog.class); // (2)设置类成员别名 <id>1</id> 改为<userId>1</userId> xstream.aliasField("userId", User.class, "id"); // (3)把LoginLog的userId属性视为xml属性,默认为xml的元素 xstream.aliasAttribute(LoginLog.class, "userId", "id"); xstream.useAttributeFor(LoginLog.class, "userId"); // (4)去掉集合类型生成XML的父节点,即忽略xml中的<logs></logs>标记 xstream.addImplicitCollection(User.class, "logs"); } /** * * * @Title: getUser * * @Description: 初始化转换对象 * * @return * * @return: User * @throws ParseException */ public static User getUser() throws ParseException { LoginLog log = new LoginLog(); log.setIp("127.0.0.1"); log.setLoginLogId(99); log.setUserId(1); log.setLoginDate(new Date()); LoginLog log2 = new LoginLog(); log2.setIp("192.168.1.1"); log2.setLoginLogId(22); log2.setUserId(2); log2.setLoginDate(new Date()); User user = new User(); user.setId(1); user.setUserName("Artisan"); user.setPassword("artisan"); user.setCredits(1000); user.setLastVisit(new Date()); user.addLoginLog(log); user.addLoginLog(log2); return user; } /** * * * @Title: objectToXml * * @Description: Java对象转换成XML * * @throws Exception * * @return: void */ public static void objectToXml() throws Exception { // 获取转换的User对象实例 User user = getUser(); // 输出内容到控制台,查看一下 System.out.println(xstream.toXML(user)); } public static void main(String[] args) throws Exception { objectToXml(); } }
输出如下
<user> <userId>1</userId> <userName>Artisan</userName> <password>artisan</password> <credits>1000</credits> <lastVisit>2017-12-06 12:32:06.504 UTC</lastVisit> <loginLog id="1"> <loginLogId>99</loginLogId> <ip>127.0.0.1</ip> <loginDate>2017-12-06 12:32:06.504 UTC</loginDate> </loginLog> <loginLog id="2"> <loginLogId>22</loginLogId> <ip>192.168.1.1</ip> <loginDate>2017-12-06 12:32:06.504 UTC</loginDate> </loginLog> </user>
可以看到时间格式如下:
2017-12-06 12:32:06.504 UTC
UTC与格林尼治平均时(GMT, Greenwich Mean Time)一样,都与英国伦敦的本地时相同,UTC + 时区差=本地时间
如果我们希望显示北京时间呢?
就需要用到转换器了
package com.xgj.oxm.xstream.quickDemo.convert; import java.text.SimpleDateFormat; import java.util.Date; import java.util.GregorianCalendar; import java.util.Locale; import com.thoughtworks.xstream.converters.ConversionException; 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 class DateConverter implements Converter { private Locale locale; public DateConverter(Locale locale) { super(); this.locale = locale; } /** * 重写该方法,判断需要转换的类型 */ @Override public boolean canConvert(Class type) { return Date.class.isAssignableFrom(type); } /** * 重写该方法,编写Java 到 XML 的转换逻辑 */ @Override public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { // DateFormat format = DateFormat.getDateInstance(DateFormat.DATE_FIELD, // this.locale); SimpleDateFormat format = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss", this.locale); writer.setValue(format.format(source)); } /** * 重写该方法,编写XML 到 Java 的转换逻辑 */ @Override public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { GregorianCalendar calendar = new GregorianCalendar(); // DateFormat format = DateFormat.getDateInstance(DateFormat.DATE_FIELD, // this.locale); SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", this.locale); try { calendar.setTime(format.parse(reader.getValue())); } catch (Exception e) { throw new ConversionException(e.getMessage(), e); } return calendar.getGregorianChange(); } }
解析
- 通过 canConvert 方法来判断转换逻辑
- 通过marshal方法,完成对象编组(对象转XML)操作的处理逻辑
- 通过unmarshal方法,完成对象f反编组(XML转对象)操作的处理逻辑
- 最后调用registerConverter方法注册自定义的转换器
修改生成xml的代码注册转换器,完整代码如下
package com.xgj.oxm.xstream.quickDemo.convert; import java.text.ParseException; import java.util.Date; import java.util.Locale; import com.thoughtworks.xstream.XStream; import com.xgj.oxm.xstream.quickDemo.domain.LoginLog; import com.xgj.oxm.xstream.quickDemo.domain.User; public class XStreamConverterDemo { private static XStream xstream; static { // 创建一个Xstream实例,使用默认的XPP解析器 xstream = new XStream(); // (1)设置类别名,修改默认的全限定名的名称 xstream.alias("user", User.class); xstream.alias("loginLog", LoginLog.class); // (2)设置类成员别名 <id>1</id> 改为<userId>1</userId> xstream.aliasField("userId", User.class, "id"); // (3)把LoginLog的userId属性视为xml属性,默认为xml的元素 xstream.aliasAttribute(LoginLog.class, "userId", "id"); xstream.useAttributeFor(LoginLog.class, "userId"); // (4)去掉集合类型生成XML的父节点,即忽略xml中的<logs></logs>标记 xstream.addImplicitCollection(User.class, "logs"); // 注册转换器 xstream.registerConverter(new DateConverter(Locale.CHINESE)); } /** * * * @Title: getUser * * @Description: 初始化转换对象 * * @return * * @return: User * @throws ParseException */ public static User getUser() throws ParseException { LoginLog log = new LoginLog(); log.setIp("127.0.0.1"); log.setLoginLogId(99); log.setUserId(1); log.setLoginDate(new Date()); LoginLog log2 = new LoginLog(); log2.setIp("192.168.1.1"); log2.setLoginLogId(22); log2.setUserId(2); log2.setLoginDate(new Date()); User user = new User(); user.setId(1); user.setUserName("Artisan"); user.setPassword("artisan"); user.setCredits(1000); user.setLastVisit(new Date()); user.addLoginLog(log); user.addLoginLog(log2); return user; } /** * * * @Title: objectToXml * * @Description: Java对象转换成XML * * @throws Exception * * @return: void */ public static void objectToXml() throws Exception { // 获取转换的User对象实例 User user = getUser(); // 输出内容到控制台,查看一下 System.out.println(xstream.toXML(user)); } public static void main(String[] args) throws Exception { objectToXml(); } }
输出
<user> <userId>1</userId> <userName>Artisan</userName> <password>artisan</password> <credits>1000</credits> <lastVisit>2017-12-06 20:34:42</lastVisit> <loginLog id="1"> <loginLogId>99</loginLogId> <ip>127.0.0.1</ip> <loginDate>2017-12-06 20:34:42</loginDate> </loginLog> <loginLog id="2"> <loginLogId>22</loginLogId> <ip>192.168.1.1</ip> <loginDate>2017-12-06 20:34:42</loginDate> </loginLog> </user>
可以看到时间已经是 2017-12-06 20:34:42 北京时间了。 转换器起作用了。
示例源码
代码已托管到Github—> https://github.com/yangshangwei/SpringMaster