寫接口過程當中,xml和json是最基本的兩種返回類型。html
fastjson能夠很方便的解決json和Pojo之間的轉換,咱們就但願再找一個實現xml和Pojo之間轉換的庫,這樣就能將實例化的對象,根據接口請求返回數據類型,直接轉換成相應格式的返回值。一方面提升開發速度,另外一方面後期方便維護。java
最終決定使用thoughtworks的XStream庫。微信開發中用了一段時間,由於微信涉及的xml格式比較簡單,不少問題沒有出現,如今開發API接口過程當中,一些基本問題就出現了。git
一、 Annotation無效github
開始爲了將Pojo對應屬性名改爲想要的,都是使用alias:apache
xstream.alias("item", Item.class);
這樣使用太麻煩,最好使用註解json
二、 這裏是列表文本文本內容沒法增長<![CDATA[這是文本]]>微信
從慣例來看,這裏最好使用CDATA包裹微信開發
三、 若是Pojo屬性包含下劃線,生成的xml變成雙下劃線maven
Pojo屬性,不包含下劃線,就不會有這個問題。若是是新項目建議不要使用下劃線,駝峯式仍是首選的。ide
XStream stream = new XStream(); xstream.processAnnotations(RendezvousMessage.class);//須要主動調用xstream方法處理類的註解
二、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{ } }
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<String> CDATA_FIELD = new ArrayList<String>(); private static List<Class<?>> CLASS_ARRAY = new ArrayList<Class<?>>(); private static final String[] packageUrlArray = new String[]{"net.oschina.job.jsonBean"}; static{ List<String> nameOfClasses = new ArrayList<String>(); for(String packageUrl : packageUrlArray){ if(StringUtils.isBlank(packageUrl)){ continue; } Set<String> 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); } }
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<String> CDATA_FIELDS; private static XmlFriendlyNameCoder nameCoder = new XmlFriendlyNameCoder("_-", "_"); /** * 構造函數 * @param _CDATA_FIELDS */ public CustomizedDomDriver(List<String> _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("<![CDATA["); writer.write(text); writer.write("]]>"); }else{ writer.write(text); } } }; } }
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<String> getClassName(String packageName, boolean isRecursion) { Set<String> 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<String> getClassNameFromDir(String filePath, String packageName, boolean isRecursion) { Set<String> className = new HashSet<String>(); 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<String> getClassNameFromJar(Enumeration<JarEntry> jarEntries, String packageName, boolean isRecursion){ Set<String> classNames = new HashSet<String>(); 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<String> getClassNameFromJars(URL[] urls, String packageName, boolean isRecursion) { Set<String> classNames = new HashSet<String>(); 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<String> classSet = ClassTool.getClassName("net.oschina.job.jsonBean", false); for(String cl: classSet){ System.out.println(cl); } } }
/** * Construct a new XmlFriendlyNameCoder. * * @since 1.4 */ public XmlFriendlyNameCoder() { this("_-", "__"); }
因此代碼從新定義XmlFriendlyNameCoder()
參考內容
資源