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