`
cjm0000000
  • 浏览: 32123 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

XStream注解方式实现生成的XML带CDATA标签

阅读更多

最近在实现微信公众接口的时候,用到了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

2
0
分享到:
评论
5 楼 转转beta 2014-11-04  
这种方式有一个缺陷,就是如果类里有参数是List<Model>的形式,那么Model里的字段并不能正确的使用注解
4 楼 zhangjjie 2014-08-21  
内部类有问题,CDATA标签注解加了没用
3 楼 weixinjie 2014-05-21  
@cjm0000000 谢谢提供。
不过程序当中有个bug,needCDATA方法的while循环
      while(!superClass.equals(Object.class)){  
            cdata = existsCDATA(superClass, fieldAlias);  
            if(cdata) return cdata;  
            [color=red]superClass = superClass.getClass().getSuperclass();[/color]  
        }  

这里传值targetClass是class的一个实例,superClass.getClass().getSuperclass()得到的是Object,为Class类的父类。
正确的写法应该是
superClass = superClass.getSuperclass();

不然继承深度三级以上会出现问题。
2 楼 cjm0000000 2014-01-14  
jurnzhou 写道
大哥,第二段代码是新建一个类吗?

是新建一个XStream实例。
1 楼 jurnzhou 2014-01-10  
大哥,第二段代码是新建一个类吗?

相关推荐

Global site tag (gtag.js) - Google Analytics