最近在实现微信公众接口的时候,用到了XStream来实现java Object和XML的相互转换,由于生成的XML需要用到CDATA标签,于是对XPPDriver做了一点扩展,用于支持自定义的注解。
第一步,需要创建自己的标签类XStreamCDATA,用于标记需要加入CDATA标签的field,代码如下:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface XStreamCDATA {
}
第二步,改写XPPDriver,通过Java反射的方式去查找打上XStreamCDATA标签的field,同时需要注意这个field是否也打上了XStreamAlias标签,需要对这种情况做处理,代码如下:
public static XStream createXstream() {
return new XStream(new XppDriver() {
@Override
public HierarchicalStreamWriter createWriter(Writer out) {
return new PrettyPrintWriter(out) {
boolean cdata = false;
Class<?> targetClass = null;
@Override
public void startNode(String name,
@SuppressWarnings("rawtypes") Class clazz) {
super.startNode(name, clazz);
//业务处理,对于用XStreamCDATA标记的Field,需要加上CDATA标签
if(!name.equals("xml")){//代表当前处理节点是class,用XstreamAlias把class的别名改成xml,下面的代码片段有提到
cdata = needCDATA(targetClass, name);
}else{
targetClass = clazz;
}
}
@Override
protected void writeText(QuickWriter writer, String text) {
if (cdata) {
writer.write(cDATA(text));
} else {
writer.write(text);
}
}
};
}
});
}
private static boolean needCDATA(Class<?> targetClass, String fieldAlias){
boolean cdata = false;
//first, scan self
cdata = existsCDATA(targetClass, fieldAlias);
if(cdata) return cdata;
//if cdata is false, scan supperClass until java.lang.Object
Class<?> superClass = targetClass.getSuperclass();
while(!superClass.equals(Object.class)){
cdata = existsCDATA(superClass, fieldAlias);
if(cdata) return cdata;
superClass = superClass.getClass().getSuperclass();
}
return false;
}
private static boolean existsCDATA(Class<?> clazz, String fieldAlias){
//scan fields
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
//1. exists XStreamCDATA
if(field.getAnnotation(XStreamCDATA.class) != null ){
XStreamAlias xStreamAlias = field.getAnnotation(XStreamAlias.class);
//2. exists XStreamAlias
if(null != xStreamAlias){
if(fieldAlias.equals(xStreamAlias.value()))//matched
return true;
}else{// not exists XStreamAlias
if(fieldAlias.equals(field.getName()))
return true;
}
}
}
return false;
}
用上面的方式初始化xstream,在需要加入CDATA标签的field加入注解,代码如下:
@XStreamAlias("xml")
public class WeiXinMessage implements Message {
/** ToUserName */
@XStreamAlias("ToUserName")
@XStreamCDATA
protected String toUserName;
/** FromUserName */
@XStreamAlias("FromUserName")
@XStreamCDATA
protected String fromUserName;
/** CreateTime */
@XStreamAlias("CreateTime")
protected long createTime;
/** MsgType */
@XStreamAlias("MsgType")
@XStreamCDATA
protected String msgType;
对于上面的Java Bean在转成XML的时候,ToUserName,FromUserName,MsgType这3个field会打上CDATA标签,以下是测试代码:
XStream xStream = WXXStreamHelper.createXstream();
xStream.processAnnotations(WeiXinMessage.class);
WeiXinMessage msgObj = ...//构造一个WeiXinMessage对象
String xml = xStream.toXML(msgObj);
【版权申明】
本文出自ITEYE BLOG,转载请注明出处:http://qurey.iteye.com/blog/1935897