http://xstream.codehaus.org
XStream是一个序列化对象为XML或XML转换为对象的库.
特点:
简化的API;
无映射文件;
高性能,低内存占用;
整洁的XML;
不需要修改对象;支持内部私有字段,不需要setter/getter方法,final字段;非公有类,内部类;类不需要默认构造器,完全对象图支持.维护对象引用计数,循环引用. i
提供序列化接口;
自定义转换类型策略;
详细的错误诊断;
快速输出格式;当前支持 JSON 和 morphing.
使用场景
Transport 转换
Persistence 持久化对象
Configuration 配置
Unit Tests 单元测试
限制
enhanced 模式: JDK版本 不能<1.5.
虽然预处理注解是安全的,但自动侦查注解可能发生竞争条件.
两分钟简单教程
http://xstream.codehaus.org/tutorial.html
XML解析器
1. XPP3 (需要 xpp3-[version].jar)
XStream xstream = new XStream(new XppDriver());
2. JAXP DOM
XStream xstream = new XStream(new DomDriver());
类型别名Alias
XStream 默认使用完全限制类名作为XML的元素名称.通过使用别名可修改元素名称为指定名称.
xstream.alias("person", Person.class);
xstream.alias("phonenumber", PhoneNumber.class);
字段别名
Stream 默认使用字段名, 优先级高于类型.
集合字段中的对象默认使用类型别名.
xstream.aliasField("phonenumber", Person.class, "phone");
注意: Person.class 是包含此字段的类,而不是字段的类型.字段是phone, 别名是phonenumber. 下面也是如此.
序列化与反序列化
对象不需要实现序列化接口. 反序列的对象与原对象不是同一对象.
String xml = xstream.toXML(obj);
T obj = (T)xstream.fromXML(xml);
隐式集合
当我们使用集合类时不想显示集合,只显示里面的元素即可.
使用隐式集合前:
<list>
<element />
<element />
<list>
使用隐式集合:
xstream.addImplicitCollection(Person.class, "list");
使用隐式集合后:
<element />
<element />
XML属性
将类的字段转换成类映射元素的一个属性,而不是元素.
xstream.useAttributeFor(Blog.class, "author");
xstream.registerConverter(new AuthorConverter()); // 注册将对象转换成字符串的转换类.
class AuthorConverter implements SingleValueConverter {
public String toString(Object obj) {
return ((Author) obj).getName();
}
public Object fromString(String name) {
return new Author(name);
}
public boolean canConvert(Class type) {
return type.equals(Author.class);
}
}
SingleValueConverter 转换成简单字符串
Converter 转换成对象
包别名
xstream.aliasPackage("my.company", "org.thoughtworks");
注解
@XStreamAlias("message") 别名注解
作用目标: 类,字段
@XStreamImplicit 隐式集合
@XStreamImplicit(itemFieldName="part")
作用目标: 集合字段
@XStreamConverter(SingleValueCalendarConverter.class) 注入转换器
作用目标: 对象
@XStreamAsAttribute 转换成属性
作用目标: 字段
@XStreamOmitField 忽略字段
作用目标: 字段
Auto-detect Annotations 自动侦查注解
xstream.autodetectAnnotations(true);
自动侦查注解与XStream.processAnnotations(Class[] cls)的区别在于性能.自动侦查注解将缓存所有类的类型.
对象流
bjectOutputStream out = xstream.createObjectOutputStream(someWriter);
ObjectInputStream in = xstream.createObjectInputStream(someReader);
持久化对象
public void persist(String dir, List objects)
{
PersistenceStrategy strategy = new FilePersistenceStrategy(new File(System.getProperty("user.home"), dir));
List<?> list = new XmlArrayList(strategy);
list.addAll(objects);
}
JSON
解析器:
Jettison StAX
XStreamFacade.java
package cn.bisoft.java.test;
import java.io.File;
import java.util.List;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.json.JettisonMappedXmlDriver;
import com.thoughtworks.xstream.io.json.JsonHierarchicalStreamDriver;
import com.thoughtworks.xstream.io.xml.DomDriver;
import com.thoughtworks.xstream.io.xml.XppDriver;
import com.thoughtworks.xstream.persistence.FilePersistenceStrategy;
import com.thoughtworks.xstream.persistence.PersistenceStrategy;
import com.thoughtworks.xstream.persistence.XmlArrayList;
public class XStreamFacade
{
private static XStream xstream;
public static final String JAXP_DOM_XML = "JAXP DOM";
public static final String XPP3_XML_PARSER = "XPP3";
public static final String STAX_JSON_PARSER = "Jettison StAX";
public static final String WRITER_JSON_PARSER = "Only Writer JSON";
public synchronized static XStream getXStream(String driver)
{
if (JAXP_DOM_XML.equals(driver))
{
xstream = new XStream(new DomDriver());
xstream.autodetectAnnotations(true);
}
else if (XPP3_XML_PARSER.equals(driver))
{
xstream = new XStream(new XppDriver());
xstream.autodetectAnnotations(true);
}
else if (STAX_JSON_PARSER.equals(driver))
{
xstream = new XStream(new JettisonMappedXmlDriver());
xstream.setMode(XStream.NO_REFERENCES);
}
else if (WRITER_JSON_PARSER.equals(driver))
{
xstream = new XStream(new JsonHierarchicalStreamDriver());
xstream.setMode(XStream.NO_REFERENCES);
}
else
{
xstream = new XStream(new DomDriver());
}
return xstream;
}
@SuppressWarnings("unchecked")
public void persist(String dir, List objects)
{
PersistenceStrategy strategy = new FilePersistenceStrategy(new File(System.getProperty("user.home"), dir));
List<?> list = new XmlArrayList(strategy);
list.addAll(objects);
}
}
------------
扩展:
1.
XBird
2.
XStream.XPATH_RELATIVE_REFERENCES
(Default) Uses relative XPath references to signify duplicate references. This produces XML with the least clutter.
XStream.XPATH_ABSOLUTE_REFERENCES
Uses absolute XPath references to signify duplicate references. This might produce for some situations better readable XML. Note, that XStream will read XML with relative paths as well as with absolute paths independent of the XPATH mode.
XStream.ID_REFERENCES
Uses ID references to signify duplicate references. In some scenarios, such as when using hand-written XML, this is easier to work with.
XStream.NO_REFERENCES
This disables object graph support and treats the object structure like a tree. Duplicate references are treated as two separate objects and circular references cause an exception. This is slightly faster and uses less memory than the other two modes.
3.
转换器
示例
XStreamFacade.java
package cn.bisoft.java.test;
import java.io.File;
import java.util.List;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.reflection.ReflectionProvider;
import com.thoughtworks.xstream.converters.reflection.Sun14ReflectionProvider;
import com.thoughtworks.xstream.io.json.JettisonMappedXmlDriver;
import com.thoughtworks.xstream.io.json.JsonHierarchicalStreamDriver;
import com.thoughtworks.xstream.io.xml.DomDriver;
import com.thoughtworks.xstream.io.xml.XppDriver;
import com.thoughtworks.xstream.persistence.FilePersistenceStrategy;
import com.thoughtworks.xstream.persistence.PersistenceStrategy;
import com.thoughtworks.xstream.persistence.XmlArrayList;
/**
* XStreamFacade
*
* <pre>
* 提供对XStream的初始化,降低使用XStream API的复杂性.
* @link
* </pre>
* @author tl
* @version 1.0, 2011-6-10
*/
public class XStreamFacade
{
public static final String JAXP_DOM_XML = "JAXP DOM";
public static final String XPP3_XML_PARSER = "XPP3";
public static final String STAX_JSON_PARSER = "Jettison StAX";
public static final String WRITER_JSON_PARSER = "Only Writer JSON";
/**
* 获取XStream对象.
*
* <pre>
* 根据驱动获取XStream对象,若没有提供驱动,则默认使用JAXP-DOM驱动.
* </pre>
* @param driver 驱动名称
* @param isStaticSupported 是否支持静态变量转换
* @return XStream
*/
public synchronized static XStream getXStream(String driver, boolean isStaticSupported)
{
ReflectionProvider reflectProvider = null;
if (isStaticSupported)
{
reflectProvider = new EnhancedModeReflectProvider();
}
else
{
reflectProvider = new Sun14ReflectionProvider();
}
if (JAXP_DOM_XML.equals(driver))
{
xstream = new XStream(reflectProvider, new DomDriver());
xstream.autodetectAnnotations(true);
System.err.println(xstream.getReflectionProvider());
}
else if (XPP3_XML_PARSER.equals(driver))
{
xstream = new XStream(reflectProvider, new XppDriver());
xstream.autodetectAnnotations(true);
}
else if (STAX_JSON_PARSER.equals(driver))
{
xstream = new XStream(reflectProvider, new JettisonMappedXmlDriver());
xstream.setMode(XStream.NO_REFERENCES);
}
else if (WRITER_JSON_PARSER.equals(driver))
{
xstream = new XStream(reflectProvider, new JsonHierarchicalStreamDriver());
xstream.setMode(XStream.NO_REFERENCES);
}
else
{
xstream = new XStream(reflectProvider, new DomDriver());
}
return xstream;
}
/**
* 持久化对象列表.
*
* <pre>
* 持久化对象列表,存储到指定用户主目录下的指定目录
* </pre>
* @param dir 目录
* @param objects 对象列表
*/
@SuppressWarnings("unchecked")
public void persist(String dir, List objects)
{
PersistenceStrategy strategy = new FilePersistenceStrategy(new File(System.getProperty("user.home"), dir));
List<?> list = new XmlArrayList(strategy);
list.addAll(objects);
}
// prinvate fields.
private static XStream xstream;
}
EnhancedModeReflectProvider.java
/**
* <pre>
* Title: EnhancedModeReflectProvider.java
* Author: tl
* Create: 2011-6-10 下午02:50:18
* Copyright: Copyright (c) 2011
* Company: Shenzhen *****
* <pre>
*/
package cn.bisoft.java.test;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import com.thoughtworks.xstream.converters.reflection.Sun14ReflectionProvider;
/**
* <pre>
* 支持静态字段转换,但有缺陷,字段不能映射成属性.
* </pre>
* @author tl
* @version 1.0, 2011-6-10
*/
public class EnhancedModeReflectProvider extends Sun14ReflectionProvider
{
@Override
protected boolean fieldModifiersSupported(Field field)
{
return !(Modifier.isTransient(field.getModifiers()));
}
}
ExampleMessageBody.java
package cn.bisoft.java.test;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
import com.thoughtworks.xstream.annotations.XStreamInclude;
import com.thoughtworks.xstream.annotations.XStreamOmitField;
@SuppressWarnings("unused")
@XStreamAlias("body")
public class ExampleMessageBody
{
@XStreamAsAttribute
private static final String type = "example";
private String id = "message id";
private Date timestamp;
/** 当userList节点必须存在是, 需要初始化. 值为空的字段是不会输出到XML的. */
@XStreamAlias("users")
private List<User> userList = new ArrayList<User>();
@XStreamAlias("user")
public static class User
{
@XStreamAsAttribute
private String id;
@XStreamAsAttribute
private Date birth;
@XStreamOmitField
private String password;
public String getId()
{
return id;
}
public void setId(String id)
{
this.id = id;
}
public Date getBirth()
{
return birth;
}
public void setBirth(Date birth)
{
this.birth = birth;
}
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = password;
}
}
public String getId()
{
return id;
}
public void setId(String id)
{
this.id = id;
}
public Date getTimestamp()
{
return timestamp;
}
public void setTimestamp(Date timestamp)
{
this.timestamp = timestamp;
}
public List<User> getUserList()
{
return userList;
}
public void setUserList(List<User> userList)
{
this.userList = userList;
}
}
TestXStream.java
package cn.bisoft.java.test;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import com.thoughtworks.xstream.XStream;
public class TestXStream
{
public static void main(String[] args)
{
XStream xstream = XStreamFacade.getXStream(XStreamFacade.JAXP_DOM_XML, true);
ExampleMessageBody body = new ExampleMessageBody();
body.setId("0");
body.setTimestamp(new Date());
List<ExampleMessageBody.User> userList = new ArrayList<ExampleMessageBody.User>();
ExampleMessageBody.User user = new ExampleMessageBody.User();
user.setBirth(new Date());
user.setId("tl");
user.setPassword("123456");
userList.add(user);
body.setUserList(userList);
xstream.useAttributeFor("type", ExampleMessageBody.class);
String xml = xstream.toXML(body);
System.out.println(xml);
}
}
说明:
1. 静态字段其实没有必要序列化.
2. 集合类型通常需要进行初始化.