博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
XStream使用中的几个问题
阅读量:6552 次
发布时间:2019-06-24

本文共 9035 字,大约阅读时间需要 30 分钟。

hot3.png

一、背景

写接口过程中,xml和json是最基本的两种返回类型。

fastjson可以很方便的解决json和Pojo之间的转换,我们就希望再找一个实现xml和Pojo之间转换的库,这样就能将实例化的对象,根据接口请求返回数据类型,直接转换成相应格式的返回值。一方面提高开发速度,另一方面后期方便维护。

最终决定使用。微信开发中用了一段时间,因为微信涉及的xml格式比较简单,很多问题没有出现,现在开发API接口过程中,一些基本问题就出现了。

二、问题

1、 Annotation无效

开始为了将Pojo对应属性名改成想要的,都是使用alias:

xstream.alias("item", Item.class);

这样使用太麻烦,最好使用注解

2、 这里是列表文本文本内容无法增加<![CDATA[这是文本]]>

从惯例来看,这里最好使用CDATA包裹

3、 如果Pojo属性包含下划线,生成的xml变成双下划线

Pojo属性,不包含下划线,就不会有这个问题。如果是新项目建议不要使用下划线,驼峰式还是首选的。

三、解决方法

  1. 官方文档就有,只是不知道:
XStream stream = new XStream();xstream.processAnnotations(RendezvousMessage.class);//需要主动调用xstream方法处理类的注解

2、3. 我们来实现对需要CDATA包裹的属性,添加注解@XStreamCDATA()

  • 这里是列表文本定义注解名称
package net.oschina.weixin.tool;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;public class XStreamAnnotation {	/**	 * 为属性增加CDATA包围	 * @author buxianglong	 * @date 2015年10月21日 下午2:43:44	 */	@Target(ElementType.FIELD)	@Retention(RetentionPolicy.RUNTIME)	public @interface XStreamCDATA{	}}
  • 自动获取所有@XStreamCDATA注解的属性
package net.oschina.weixin.tool;import java.lang.reflect.Field;import java.util.ArrayList;import java.util.List;import java.util.Set;import org.apache.commons.lang3.StringUtils;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import com.thoughtworks.xstream.XStream;public class XmlTool {	private static final Log logger = LogFactory.getLog(XmlTool.class);	private static XStream xstream;	private static List
CDATA_FIELD = new ArrayList
(); private static List
> CLASS_ARRAY = new ArrayList
>(); private static final String[] packageUrlArray = new String[]{"net.oschina.job.jsonBean"}; static{ List
nameOfClasses = new ArrayList
(); for(String packageUrl : packageUrlArray){ if(StringUtils.isBlank(packageUrl)){ continue; } Set
result = ClassTool.getClassName(packageUrl, false); if(result != null && result.size() > 0){ nameOfClasses.addAll(result); } } if(nameOfClasses != null && nameOfClasses.size() > 0){ for(String nameOfClass : nameOfClasses){ try { Class
myClass = Class.forName(nameOfClass); CLASS_ARRAY.add(myClass); //获取自定义注解的属性集合 Field[] fieldArray = myClass.getDeclaredFields(); if(fieldArray != null && fieldArray.length > 0){ for(Field field : fieldArray){ if(field != null && field.isAnnotationPresent(XStreamAnnotation.XStreamCDATA.class)){ CDATA_FIELD.add(field.getName()); } } } } catch (ClassNotFoundException e) { logger.error("net.oschina.weixin.tool.XmlTool.java **XStream** init failed!"); e.printStackTrace(); } } } //实例化XStream对象 xstream = new XStream(new CustomizedDomDriver(CDATA_FIELD)); //处理自带注解 if(CLASS_ARRAY != null && CLASS_ARRAY.size() > 0){ for(Class
myClass : CLASS_ARRAY){ if(myClass != null){ xstream.processAnnotations(myClass); } } } } /** * xml转为对象 * @param xml * @return */ public static Object parseXmlToObj(String xml, @SuppressWarnings("rawtypes") Class type){ xstream.alias("xml", type); return xstream.fromXML(xml); } /** * 对象转为xml * @param obj * @return */ public static String parseObjToXml(Object obj){ xstream.alias("xml", obj.getClass()); return xstream.toXML(obj); }}
  • 扩展DomDriver,重写createWriter(Writer out)方法
package net.oschina.weixin.tool;import java.io.Writer;import java.util.List;import com.thoughtworks.xstream.core.util.QuickWriter;import com.thoughtworks.xstream.io.HierarchicalStreamWriter;import com.thoughtworks.xstream.io.xml.DomDriver;import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder;public class CustomizedDomDriver extends DomDriver{	 private List
CDATA_FIELDS; private static XmlFriendlyNameCoder nameCoder = new XmlFriendlyNameCoder("_-", "_"); /** * 构造函数 * @param _CDATA_FIELDS */ public CustomizedDomDriver(List
_CDATA_FIELDS){ this.CDATA_FIELDS = _CDATA_FIELDS; } @Override public HierarchicalStreamWriter createWriter(Writer out){ return new PrettyPrintWriter(out, nameCoder){ boolean cdata = false; public void startNode(String name){ super.startNode(name); cdata = CDATA_FIELDS.contains(name); } protected void writeText(QuickWriter writer, String text){ if (cdata){ writer.write(""); }else{ writer.write(text); } } }; }}
  • 其中使用了 的Class操作类
package net.oschina.weixin.tool;import java.io.File;import java.io.IOException;import java.net.JarURLConnection;import java.net.URL;import java.net.URLClassLoader;import java.util.Enumeration;import java.util.HashSet;import java.util.Set;import java.util.jar.JarEntry;import java.util.jar.JarFile;/** * http://my.oschina.net/cnlw/blog/299265 * @author 水牛叔叔 * @date 2015年10月20日 下午3:12:49 */public class ClassTool {	/**     * 获取某包下所有类     * @param packageName 包名     * @param isRecursion 是否遍历子包     * @return 类的完整名称     */    public static Set
getClassName(String packageName, boolean isRecursion) { Set
classNames = null; ClassLoader loader = Thread.currentThread().getContextClassLoader(); String packagePath = packageName.replace(".", "/"); URL url = loader.getResource(packagePath); if (url != null) { String protocol = url.getProtocol(); if (protocol.equals("file")) { classNames = getClassNameFromDir(url.getPath(), packageName, isRecursion); } else if (protocol.equals("jar")) { JarFile jarFile = null; try{ jarFile = ((JarURLConnection) url.openConnection()).getJarFile(); } catch(Exception e){ e.printStackTrace(); } if(jarFile != null){ getClassNameFromJar(jarFile.entries(), packageName, isRecursion); } } } else { /*从所有的jar包中查找包名*/ classNames = getClassNameFromJars(((URLClassLoader)loader).getURLs(), packageName, isRecursion); } return classNames; } /** * 从项目文件获取某包下所有类 * @param filePath 文件路径 * @param className 类名集合 * @param isRecursion 是否遍历子包 * @return 类的完整名称 */ private static Set
getClassNameFromDir(String filePath, String packageName, boolean isRecursion) { Set
className = new HashSet
(); File file = new File(filePath); File[] files = file.listFiles(); for (File childFile : files) { if (childFile.isDirectory()) { if (isRecursion) { className.addAll(getClassNameFromDir(childFile.getPath(), packageName+"."+childFile.getName(), isRecursion)); } } else { String fileName = childFile.getName(); if (fileName.endsWith(".class") && !fileName.contains("$")) { className.add(packageName+ "." + fileName.replace(".class", "")); } } } return className; } /** * @param jarEntries * @param packageName * @param isRecursion * @return */ private static Set
getClassNameFromJar(Enumeration
jarEntries, String packageName, boolean isRecursion){ Set
classNames = new HashSet
(); while (jarEntries.hasMoreElements()) { JarEntry jarEntry = jarEntries.nextElement(); if(!jarEntry.isDirectory()){ /* * 这里是为了方便,先把"/" 转成 "." 再判断 ".class" 的做法可能会有bug * (FIXME: 先把"/" 转成 "." 再判断 ".class" 的做法可能会有bug) */ String entryName = jarEntry.getName().replace("/", "."); if (entryName.endsWith(".class") && !entryName.contains("$") && entryName.startsWith(packageName)) { entryName = entryName.replace(".class", ""); if(isRecursion){ classNames.add(entryName); } else if(!entryName.replace(packageName+".", "").contains(".")){ classNames.add(entryName); } } } } return classNames; } /** * 从所有jar中搜索该包,并获取该包下所有类 * @param urls URL集合 * @param packageName 包路径 * @param isRecursion 是否遍历子包 * @return 类的完整名称 */ private static Set
getClassNameFromJars(URL[] urls, String packageName, boolean isRecursion) { Set
classNames = new HashSet
(); for (int i = 0; i < urls.length; i++) { String classPath = urls[i].getPath(); //不必搜索classes文件夹 if (classPath.endsWith("classes/")) {continue;} JarFile jarFile = null; try { jarFile = new JarFile(classPath.substring(classPath.indexOf("/"))); } catch (IOException e) { e.printStackTrace(); } if (jarFile != null) { classNames.addAll(getClassNameFromJar(jarFile.entries(), packageName, isRecursion)); } } return classNames; } public static void main(String[] args) { Set
classSet = ClassTool.getClassName("net.oschina.job.jsonBean", false); for(String cl: classSet){ System.out.println(cl); } }}
  • 关于下划线转换成双下划线的问题,查看xstream的源代码:
/**  * Construct a new XmlFriendlyNameCoder.  *   * @since 1.4  */  public XmlFriendlyNameCoder() {      this("_-", "__");  }

所以代码重新定义XmlFriendlyNameCoder()

四、参考

参考内容

资源

转载于:https://my.oschina.net/ijustdoit/blog/520719

你可能感兴趣的文章
Linux平台下可视化压测软件visual-wrk
查看>>
我的提交信息规范
查看>>
OSChina 周五乱弹 ——程序员看火影忍者被女同事鄙视了
查看>>
OSChina 周四乱弹 ——PM是这样学程序的
查看>>
OSChina 周四乱弹 —— 只有食物才能收买我的灵魂
查看>>
依赖倒置原则
查看>>
Yarn的原理与资源调度
查看>>
SQL练习题
查看>>
该如何用好Automator中的文件夹操作
查看>>
pdf转换成word转换器免费版
查看>>
windows环境软件下载
查看>>
spring boot jpa mysql 解决中文乱码
查看>>
oh-my-zsh小记
查看>>
用JAX-WS开发WebService服务端并用tomcat发布Web服务
查看>>
数据库事务并发与锁详解
查看>>
Spring annotation 、Spring 注解、注册注解处理器
查看>>
RHEL DNS
查看>>
python print
查看>>
配置SSH 安全管理 Cisco Switch
查看>>
Voice Lab 3-IPhone Features & CME Features
查看>>