xstream简单实用
2013-06-07 17:03
429 查看
XStream是一个将对象序列化为xml并解析xml为对象的框架,主页位于http://xstream.codehaus.org。使用非常简单
引入依赖:
Xml代码
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.2</version>
</dependency>
需要的依赖
XmlPull一个xmlpull parser api用来判断具体的xml解析实现(DOM、StAX等)工厂
其他可供选择的Xpp3、DOM4J
1、创建待序列化的对象:
Person.java
Java代码
public class Person {
private Integer id;
private String username;
private String password;
private Address address;
...
}
Person中包含一个Address作为Field
Java代码
public class Address {
private String street;
private String city;
......
}
2、序列化和反序列化
使用XStream只需要实例化一个XStream对象即可:
Java代码
XStream xstream = new XStream();
//采用这个构造器默认需要依赖:xstream-[version].jar, xpp3-[version].jar and xmlpull-[version].jar
或者采用DOM的方式解析:
Java代码
XStream xstream = new XStream(new DomDriver());
//此时不需要XPP3
或者基于事件的StAX
Java代码
XStream xstream = new XStream(new StaxDriver());
//如果采用Java 6,也不需要xpp3.将采用默认的JAXB
Java代码
//对象序列化为xml
xstream.toXML(Object)
//xml反序列化为对象
xstream.fromXML(xml)
一个例子:
Java代码
Person p = new Person();
p.setId(1);
p.setUsername("robin");
p.setPassword("123");
p.setAddress(new Address("xxRoad", "chengdu"));
xstream.toXML(p);
输出为:
Xml代码
<org.java.codelib.xstream.Person>
<id>1</id>
<username>robin</username>
<password>123</password>
<address>
<street>xxRoad</street>
<city>chengdu</city>
</address>
</org.java.codelib.xstream.Person>
3、alias
这里可以看到生成的xml中root element名字为class,如果需要修改就需要用到
Java代码
xstream.alias("person", Person.class);
这样就会用person替代org.java.codelib.xstream.Person
同样对于field也可以使用alias:
Java代码
xstream.aliasField("personId", Person.class, "id");
这样就会将Person中的id替换为<personId>1</personId>
其他的还有aliasAttribute即将field作为attribute时并采用别名,当前前提是需要设置field作为attribute:
Java代码
XStream xstream = new XStream(new StaxDriver());
xstream.alias("person", Person.class);
xstream.useAttributeFor(Person.class, "id");
xstream.aliasAttribute("personId", "id");
xstream.toXML(p);
输出为:
Xml代码
<?xml version="1.0" ?><person personId="1"><username>robin</username><password>123</password><address><street>xxRoad</street><city>chengdu</city></address></person>
说到设置field作为attribute如果field是一个自定义对象,或者需要将Date之类的属性格式化输出,如本例中的Address该如何处理?这就是另外一个话题
需要说明的是以上在序列化为xml的时候使用了alias,那么在反序列化的时候同样需要这些相应的代码,不然可能会抛出UnknownFieldException
4、convertors
convertor的作用是在做序列化或反序列化的时候,将对象中的属性按照特定的形式输出或转化,在XStream 中默认初始化了大量的必要convertors,见http://xstream.codehaus.org/converters.html 或者在XStream.java中有方法setupConverters()。
自定义一个convertor需要两步:
1、实现Converter接口及相关方法:
Java代码
public class DateConverter implements Converter {
@Override
public boolean canConvert(Class type) {
return type.equals(Date.class);
}
@Override
public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
writer.setValue(dateFormat.format((Date) source));
}
@Override
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
return dateFormat.parse(reader.getValue());
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
2、在xstream中注册该convertor:
Java代码
xstream.registerConverter(new DateConverter());
输出
Xml代码
<?xml version="1.0" ?><person><id>1</id><username>robin</username><password>123</password><birthday>2013-02-17 15:12:53</birthday><address><street>xxRoad</street><city>chengdu</city></address></person>
当然,xstream针对Date也做了默认的实现,只不过默认输出为UTC格式
现在我们回到上面的问题,即将对象Address作为Person的属性,下面是一个convertor的实现:
Java代码
public class PersonConverter implements Converter {
@SuppressWarnings("rawtypes")
@Override
public boolean canConvert(Class type) {
return type.equals(Person.class);
}
@Override
public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
Person person = (Person) source;
if (person != null) {
Address address = person.getAddress();
if (address != null) {
if (StringUtils.isNotBlank(address.getStreet())) {
writer.addAttribute("street", address.getStreet());
}
if (StringUtils.isNotBlank(address.getCity())) {
writer.addAttribute("city", address.getCity());
}
}
//address
if (person.getBirthday() != null) {
writer.startNode("birthday");
context.convertAnother(person.getBirthday(), new DateConverter());
writer.endNode();
}
//username
if (person.getUsername() != null) {
writer.startNode("username");
context.convertAnother(person.getUsername());
writer.endNode();
}
//other fields
}
}
@Override
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
Person p = new Person();
Address address = new Address();
address.setCity(reader.getAttribute("city"));
address.setStreet(reader.getAttribute("street"));
p.setAddress(address);
while (reader.hasMoreChildren()) {
reader.moveDown();
if ("birthday".equals(reader.getNodeName())) {
Date date = (Date) context.convertAnother(p, Date.class, new DateConverter());
p.setBirthday(date);
} else if ("username".equals(reader.getNodeName())) {
p.setUsername((String) context.convertAnother(p, String.class));
}
//other fields
reader.moveUp();
}
return p;
}
}
其中序列化时输出:
Xml代码
<?xml version="1.0" ?><person street="xxRoad" city="chengdu"><birthday>2013-02-17 16:34:24</birthday><username>robin</username></person>
当然如果作为fields的对象只有一个属性就简单得多了,在http://xstream.codehaus.org/alias-tutorial.html#attributes有例子可供参考
5、implicitCollections
考虑Person有列表属性:
Java代码
private List<Address> addresses;
在序列化为xml时:
Xml代码
<?xml version="1.0" ?><person><addresses><address><street>road_1</street><city>chengdu</city></address><address><street>road_2</street><city>chengdu</city></address></addresses></person>
当然有时候并不想要addresses,这就是XStream中的implicitCollections:对集合的属性在序列化是不想显示roottag。值需要很简单的处理:
Java代码
XStream xstream = new XStream(new StaxDriver());
xstream.alias("person", Person.class);
xstream.alias("address", Address.class);
xstream.addImplicitCollection(Person.class, "addresses");
return xstream.toXML(formatPerson());
输出为:
Xml代码
<?xml version="1.0" ?><person><address><street>road_1</street><city>chengdu</city></address><address><street>road_2</street><city>chengdu</city></address></person>
6、annotation
以上说的内容都支持annotation:
Java代码
@XStreamAlias("person")
public class Person {
@XStreamAlias("personId")
@XStreamAsAttribute
private Integer id;
private String username;
private String password;
@XStreamConverter(DateConverter.class)
private Date birthday;
private Address address;
@XStreamImplicit(itemFieldName = "address")
private List<Address> addresses;
}
Java代码
@XStreamAlias("person")
public class Address {
@XStreamAsAttribute
private String street;
@XStreamAsAttribute
private String city;
}
需要加上autodetectAnnotations(true)
Java代码
XStream xstream = new XStream(new StaxDriver());
xstream.autodetectAnnotations(true);
return xstream.toXML(p);
输出:
Xml代码
<?xml version="1.0" ?><person personId="1"><username>robin</username><password>123</password><birthday>2013-02-17 17:08:00</birthday><address street="road_1" city="chengdu"></address><address street="road_2" city="chengdu"></address></person>
7、其他
xstream提供了对json的解析以及持久化(文件系统)的支持,这里就不再介绍了
引入依赖:
Xml代码
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.2</version>
</dependency>
需要的依赖
XmlPull一个xmlpull parser api用来判断具体的xml解析实现(DOM、StAX等)工厂
其他可供选择的Xpp3、DOM4J
1、创建待序列化的对象:
Person.java
Java代码
public class Person {
private Integer id;
private String username;
private String password;
private Address address;
...
}
Person中包含一个Address作为Field
Java代码
public class Address {
private String street;
private String city;
......
}
2、序列化和反序列化
使用XStream只需要实例化一个XStream对象即可:
Java代码
XStream xstream = new XStream();
//采用这个构造器默认需要依赖:xstream-[version].jar, xpp3-[version].jar and xmlpull-[version].jar
或者采用DOM的方式解析:
Java代码
XStream xstream = new XStream(new DomDriver());
//此时不需要XPP3
或者基于事件的StAX
Java代码
XStream xstream = new XStream(new StaxDriver());
//如果采用Java 6,也不需要xpp3.将采用默认的JAXB
Java代码
//对象序列化为xml
xstream.toXML(Object)
//xml反序列化为对象
xstream.fromXML(xml)
一个例子:
Java代码
Person p = new Person();
p.setId(1);
p.setUsername("robin");
p.setPassword("123");
p.setAddress(new Address("xxRoad", "chengdu"));
xstream.toXML(p);
输出为:
Xml代码
<org.java.codelib.xstream.Person>
<id>1</id>
<username>robin</username>
<password>123</password>
<address>
<street>xxRoad</street>
<city>chengdu</city>
</address>
</org.java.codelib.xstream.Person>
3、alias
这里可以看到生成的xml中root element名字为class,如果需要修改就需要用到
Java代码
xstream.alias("person", Person.class);
这样就会用person替代org.java.codelib.xstream.Person
同样对于field也可以使用alias:
Java代码
xstream.aliasField("personId", Person.class, "id");
这样就会将Person中的id替换为<personId>1</personId>
其他的还有aliasAttribute即将field作为attribute时并采用别名,当前前提是需要设置field作为attribute:
Java代码
XStream xstream = new XStream(new StaxDriver());
xstream.alias("person", Person.class);
xstream.useAttributeFor(Person.class, "id");
xstream.aliasAttribute("personId", "id");
xstream.toXML(p);
输出为:
Xml代码
<?xml version="1.0" ?><person personId="1"><username>robin</username><password>123</password><address><street>xxRoad</street><city>chengdu</city></address></person>
说到设置field作为attribute如果field是一个自定义对象,或者需要将Date之类的属性格式化输出,如本例中的Address该如何处理?这就是另外一个话题
需要说明的是以上在序列化为xml的时候使用了alias,那么在反序列化的时候同样需要这些相应的代码,不然可能会抛出UnknownFieldException
4、convertors
convertor的作用是在做序列化或反序列化的时候,将对象中的属性按照特定的形式输出或转化,在XStream 中默认初始化了大量的必要convertors,见http://xstream.codehaus.org/converters.html 或者在XStream.java中有方法setupConverters()。
自定义一个convertor需要两步:
1、实现Converter接口及相关方法:
Java代码
public class DateConverter implements Converter {
@Override
public boolean canConvert(Class type) {
return type.equals(Date.class);
}
@Override
public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
writer.setValue(dateFormat.format((Date) source));
}
@Override
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
return dateFormat.parse(reader.getValue());
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
2、在xstream中注册该convertor:
Java代码
xstream.registerConverter(new DateConverter());
输出
Xml代码
<?xml version="1.0" ?><person><id>1</id><username>robin</username><password>123</password><birthday>2013-02-17 15:12:53</birthday><address><street>xxRoad</street><city>chengdu</city></address></person>
当然,xstream针对Date也做了默认的实现,只不过默认输出为UTC格式
现在我们回到上面的问题,即将对象Address作为Person的属性,下面是一个convertor的实现:
Java代码
public class PersonConverter implements Converter {
@SuppressWarnings("rawtypes")
@Override
public boolean canConvert(Class type) {
return type.equals(Person.class);
}
@Override
public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
Person person = (Person) source;
if (person != null) {
Address address = person.getAddress();
if (address != null) {
if (StringUtils.isNotBlank(address.getStreet())) {
writer.addAttribute("street", address.getStreet());
}
if (StringUtils.isNotBlank(address.getCity())) {
writer.addAttribute("city", address.getCity());
}
}
//address
if (person.getBirthday() != null) {
writer.startNode("birthday");
context.convertAnother(person.getBirthday(), new DateConverter());
writer.endNode();
}
//username
if (person.getUsername() != null) {
writer.startNode("username");
context.convertAnother(person.getUsername());
writer.endNode();
}
//other fields
}
}
@Override
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
Person p = new Person();
Address address = new Address();
address.setCity(reader.getAttribute("city"));
address.setStreet(reader.getAttribute("street"));
p.setAddress(address);
while (reader.hasMoreChildren()) {
reader.moveDown();
if ("birthday".equals(reader.getNodeName())) {
Date date = (Date) context.convertAnother(p, Date.class, new DateConverter());
p.setBirthday(date);
} else if ("username".equals(reader.getNodeName())) {
p.setUsername((String) context.convertAnother(p, String.class));
}
//other fields
reader.moveUp();
}
return p;
}
}
其中序列化时输出:
Xml代码
<?xml version="1.0" ?><person street="xxRoad" city="chengdu"><birthday>2013-02-17 16:34:24</birthday><username>robin</username></person>
当然如果作为fields的对象只有一个属性就简单得多了,在http://xstream.codehaus.org/alias-tutorial.html#attributes有例子可供参考
5、implicitCollections
考虑Person有列表属性:
Java代码
private List<Address> addresses;
在序列化为xml时:
Xml代码
<?xml version="1.0" ?><person><addresses><address><street>road_1</street><city>chengdu</city></address><address><street>road_2</street><city>chengdu</city></address></addresses></person>
当然有时候并不想要addresses,这就是XStream中的implicitCollections:对集合的属性在序列化是不想显示roottag。值需要很简单的处理:
Java代码
XStream xstream = new XStream(new StaxDriver());
xstream.alias("person", Person.class);
xstream.alias("address", Address.class);
xstream.addImplicitCollection(Person.class, "addresses");
return xstream.toXML(formatPerson());
输出为:
Xml代码
<?xml version="1.0" ?><person><address><street>road_1</street><city>chengdu</city></address><address><street>road_2</street><city>chengdu</city></address></person>
6、annotation
以上说的内容都支持annotation:
Java代码
@XStreamAlias("person")
public class Person {
@XStreamAlias("personId")
@XStreamAsAttribute
private Integer id;
private String username;
private String password;
@XStreamConverter(DateConverter.class)
private Date birthday;
private Address address;
@XStreamImplicit(itemFieldName = "address")
private List<Address> addresses;
}
Java代码
@XStreamAlias("person")
public class Address {
@XStreamAsAttribute
private String street;
@XStreamAsAttribute
private String city;
}
需要加上autodetectAnnotations(true)
Java代码
XStream xstream = new XStream(new StaxDriver());
xstream.autodetectAnnotations(true);
return xstream.toXML(p);
输出:
Xml代码
<?xml version="1.0" ?><person personId="1"><username>robin</username><password>123</password><birthday>2013-02-17 17:08:00</birthday><address street="road_1" city="chengdu"></address><address street="road_2" city="chengdu"></address></person>
7、其他
xstream提供了对json的解析以及持久化(文件系统)的支持,这里就不再介绍了
相关文章推荐
- XStream简单实用
- XStream -- 非常简单实用的XML读写工具(一)
- 简单实用XStream--生成xml以及返回对象
- XStream的简单实用方法
- JavaScript多级下拉菜单代码(简单实用)
- XStream的简单使用
- XStream的简单使用
- 走近Flex组件系列(二):简单实用的Alert组件
- VS08中最简单也最实用的Ajax无刷新技术
- 一篇简单的实用的代码,教你如何写GPS
- 10个简单实用的 jQuery 代码片段
- redis安装与简单实用
- VS2010 简单实用快捷键
- InvokeRepeating简单实用
- 简单实用SQL脚本Part:查找SQL Server 自增ID值不连续记录
- ubuntu下实用的三大简单实用的命令~删除 复制 移动 权限不足时在前面加上sudo
- FMDB 简单实用
- 简单实用的jQuery分页插件
- C++ 之Boost 实用工具类及简单使用
- 一个简单实用的遗传算法c程序(转载)