xstream简介(bean与xml转换工具)

xstream简介(bean与xml转换工具)

本文
解决了"_"显示为"__"的问题。
解决了当xml的element属性多余bean的映射问题
解决了生成xml换行的问题

作用:
能够简单的通过
xstreamInstance.fromXML(xmlContent); 获取到对象
xstreamInstance.toXML(beanInstance); 将对象转换为xml

官网:
http://xstream.codehaus.org/

适用场景
bean与xml存在相互转换的场景:配置文件读取,报文解析,生成报文
从官方的版本演进上看,还提供了hibernate,json配置文件的读取。从1.4版本以后,新加入hibernate相关处理的逻辑,该部分功能尚未详细了解。

不适用场景
xml文件较大(比如有个10M的xml文件解析,就不太适用,因一次性解析,以及生成对象将会造成内存溢出)

效率
经过实测对象10个属性,对应xml。
xstream采用默认xml引擎,效率是dom4j解析的10倍左右(具体效率与代码实现有关,dom4j也能实现较高性能的解析)
总体来说,利用xstream能够大大提高,xml解析的入门,以及编写方便

具体事例:


如何应用:
从xstream的pom文件分析
只需要将xstream.jar xpp3.jar xmlpull.jar放入项目即可
如果为maven项目
只需要添加:
        <dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.3</version>
</dependency>


使用实例:
例子一:
定义类
public class Person {
private String firstname;
private String lastname;
private PhoneNumber phone;
private PhoneNumber fax;
// ... constructors and methods
}
public class PhoneNumber {
private int code;
private String number;
// ... constructors and methods
}


初始化解析对象
XStream xstream = new XStream();

如果不想使用xpp作为xml解析引擎,也可写为new XStream(new Dom4jDriver());
设置映射规则:
xstream.alias("person", Person.class);
xstream.alias("phonenumber", PhoneNumber.class);


将对象序列化为xml
Person joe = new Person("Joe", "Walnes");
joe.setPhone(new PhoneNumber(123, "1234-456"));
joe.setFax(new PhoneNumber(123, "9999-999"));

String xml = xstream.toXML(joe);

结果:
<person>
<firstname>Joe</firstname>
<lastname>Walnes</lastname>
<phone>
<code>123</code>
<number>1234-456</number>
</phone>
<fax>
<code>123</code>
<number>9999-999</number>
</fax>
</person>


由xml生成对象
Person newJoe = (Person)xstream.fromXML(xml);


当然xstream也支持注解,一下代码中使用到了 XstreamUtils 这个是在xstream基础上的封装,解决了现在xstream在日常使用中会出现的一些问题
    @XStreamAlias("TestBeanRoot")
class TestBean
{
private String testEl1;
@XStreamAlias("test_Rename_El2")
private String testEl2;
@XStreamAsAttribute
private String testAttr;
@XStreamOmitField
private String testSkip;
@XStreamImplicit(itemFieldName = "itemName", keyFieldName = "keyName")
private List<String> testList;
...getAndSet
}
XStream testBeanXstream = XstreamUtils.getXstream(XstreamUtilsTest.TestBean.class);
XstreamUtilsTest.TestBean tt = createTestBean();
System.out.println(testBeanXstream.toXML(tt));

"<TestBeanRoot testAttr=\"attr\">"
"<testEl1>el1</testEl1>"
+ "<test_Rename_El2>el2</test_Rename_El2>"
+ "<itemName>listItem1</itemName>"
+ "<itemName>listItem2</itemName>"
+ "</TestBeanRoot>"

如果存在多级el的情况,可以通过引用其他类的形式 如 private TestBean2 testBean2;,新的类内部又可以具有其他结构

xstream常用的注解有:
  @XStreamAlias
@XStreamAsAttribute
@XStreamOmitField
@XStreamImplicit


但看到很多文章,有这样的说法
1、xstream有bug,在转换过程中,会将 定义别名中的下划线“_”转换为xml后会变成“__”
2、在xml生成对象时,xml有多出来的元素时,对象生成将会抛出异常。

事实上从xstream源代码分析,这两个都不是问题,xstream都提供了对应的处理方式

具体参看工具类

/**
* xstream工具封装
* 用以处理xml与bean的转换
*
* @author PengQingyang
* @version [版本号, 2012-10-5]
* @see [相关类/方法]
* @since [产品/模块版本]
*/
public class XstreamUtils
{
private static Logger logger = LoggerFactory.getLogger(XstreamUtils.class);

private static Map<Class<?>, XStream> xstreamMap = new WeakHashMap<Class<?>, XStream>();

/**
* 转换过程中特殊字符转码
*/
private static NameCoder nameCoder = new NameCoder()
{
public String encodeNode(String arg0)
{
return arg0;
}

public String encodeAttribute(String arg0)
{
return arg0;
}

public String decodeNode(String arg0)
{
return arg0;
}

public String decodeAttribute(String arg0)
{
return arg0;
}
};

/**
* 在xml中多余的节点生成bean时会抛出异常
* 通过该mapperWrapper跳过不存在的属性
* @param mapper
* @return [参数说明]
*
* @return MapperWrapper [返回类型说明]
* @exception throws [异常类型] [异常说明]
* @see [类、类#方法、类#成员]
*/
private static MapperWrapper createSkipOverElementMapperWrapper(
Mapper mapper)
{
MapperWrapper resMapper = new MapperWrapper(mapper)
{
/**
* @param elementName
* @return
*/
@SuppressWarnings("rawtypes")
@Override
public Class realClass(String elementName)
{
Class res = null;
;
try
{
res = super.realClass(elementName);
}
catch (CannotResolveClassException e)
{
logger.warn("xstream change xml to object. filed (0) not exsit. ",
elementName);
}
return res;
}
};

return resMapper;
}

/**
* 获取xstream转换对象
* @param classType
* @return [参数说明]
*
* @return XStream [返回类型说明]
* @exception throws [异常类型] [异常说明]
* @see [类、类#方法、类#成员]
*/
public static XStream getXstream(Class<?> classType)
{
return getXstream(classType, true);
}

/**
* 获取xstream转换对象
* @param classType
* @param isSkipOverElement
* @return [参数说明]
*
* @return XStream [返回类型说明]
* @exception throws [异常类型] [异常说明]
* @see [类、类#方法、类#成员]
*/
public static XStream getXstream(Class<?> classType,
boolean isSkipOverElement)
{
if (xstreamMap.containsKey(classType))
{
return xstreamMap.get(classType);
}

XStream res = null;
if (isSkipOverElement)
{
res = new XStream(new Xpp3DomDriver(nameCoder))
{

/**
* @param next
* @return
*/
protected MapperWrapper wrapMapper(MapperWrapper next)
{
return createSkipOverElementMapperWrapper(next);
}

};
}
else
{
res = new XStream(new Xpp3DomDriver(nameCoder));
}

logger.info("create xstream by {0} , parameter {1}", new Object[] {
classType.getName(), isSkipOverElement });

res.processAnnotations(classType);

xstreamMap.put(classType, res);

return res;
}

}


封装后的使用:
     private static xxxxXstream = XstreamUtils.getXstream(Xxxx.class);

method(){
xxxxXstream.toXML
xxxxXstream.fromXML
}



2012-10-22追加
如果想生成的xml是否换行,自己进行控制,可这样写


/**
*<获取xstream转换对象>
*<功能详细描述>
* @param classType
* @param isSkipOverElement
* @param isNewLine
* @return [参数说明]
*
* @return XStream [返回类型说明]
* @exception throws [异常类型] [异常说明]
* @see [类、类#方法、类#成员]
*/
public static XStream getXstream(Class<?> classType,
boolean isSkipOverElement, boolean isNewLine) {
if (xstreamMap.containsKey(classType)) {
return xstreamMap.get(classType);
}

/**
* 生成domDriver 重写createWriter方法,使生成的domDriver在新的节点不会信生成一行
*/
HierarchicalStreamDriver domDriver = null;
if (isNewLine) {
domDriver = new Xpp3DomDriver(nameCoder);
} else {
domDriver = new Xpp3DomDriver(nameCoder) {
public HierarchicalStreamWriter createWriter(Writer out) {
return new PrettyPrintWriter(out, getNameCoder()) {
protected String getNewLine() {
return "";
}
};
}
};
}

XStream res = null;
if (isSkipOverElement) {
res = new XStream(domDriver) {
protected MapperWrapper wrapMapper(MapperWrapper next) {
return createSkipOverElementMapperWrapper(next);
}
};
} else {
res = new XStream(domDriver);
}

logger.info("create xstream by {0} , parameter {1}", new Object[] {
classType.getName(), isSkipOverElement });

res.processAnnotations(classType);

xstreamMap.put(classType, res);

return res;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值