我们在开发的过程中,有的时候需要转换一些自定义类型,此时默认的映射方式可能无法满足需要。
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