在java中,解析、分裝xml是一件很是「麻煩」的事。咱們經常須要寫大量的代理來解析不一樣的XML文件,而後將解析結果賦值給相關對象,便於更好的使用;或者將相關對象轉換成XML格式進行輸出。爲了減去這繁瑣的操做,筆者經過反射、註解的功能來實現 XML 與 JAVA對象 的相互轉換。 java
同時,可能存在協議的變更,某些xml標籤可能不在返回,這裏也提供經過註解,快速屏蔽bean中某些屬性的解析和分裝。大大提升了轉換的靈活度,以及便於最小程度的改動現有代碼。 git
XML ——> bean 數組
/** * 解析xml * @param c 目標對象的Class類 * @param parentObj 對象的父類,主要用於將對象set到父類中。即,遞歸地將c目標對象中的各個屬性對象進行set操做,使c目標對象屬性值爲解析結果。 * @param isCollection 是不是Collection。若是目標對象包含Collection,則定義Class的時候,須要將Collection初始化 * @param element 當前對象的Xml層對應的Element * @return 封裝好的c對象實例 * @throws Exception */ @SuppressWarnings({ "rawtypes", "unchecked" }) public static Object parseXml(Class c, Object parentObj, boolean isCollection, Element element) throws Exception { Object currentObj = null; Element currentElement = element; if (parentObj == null) { currentObj = c.newInstance(); } else if(isCollection) { currentObj = parentObj; } else { //經過c獲取className,並將className對象set到parentObj中 String[] strs = c.getName().split("\\."); strs = strs[strs.length - 1].split("\\$"); String className = strs[strs.length - 1]; element = currentElement.element(className.toUpperCase()); if(element == null) { throw new Exception("parseXml Error. target:" + className + " is not exists"); } currentObj = c.newInstance(); String setMethod = "set" + className.substring(0, 1).toUpperCase() + className.substring(1); Method method = parentObj.getClass().getDeclaredMethod(setMethod, c); method.invoke(parentObj, new Object[]{currentObj}); } Field[] fieldArray = c.getDeclaredFields(); for (Field field : fieldArray) { //若屬性標示爲無需解析,則continue if(field.isAnnotationPresent(XmlTransformAnnotation.class)) { XmlTransformAnnotation xmlAnnotation = (XmlTransformAnnotation)field.getAnnotation(XmlTransformAnnotation.class); String isParse = xmlAnnotation.value(); if(XmlTransformAnnotation.FLASE.equals(isParse)) { continue; } } Class basicType = getBasicType(field.getType()); if (basicType != null) { //屬性爲基本類型(包括:String、Integer、Byte、Short、Long、Float、Double、Character、Boolean、int、byte、short、long、float、double、char、boolean) //解析屬性xml標籤,並將解析結果賦值到currentObj中 String setMethod = "set" + field.getName().substring(0,1).toUpperCase() + field.getName().substring(1); Method method = c.getDeclaredMethod(setMethod, field.getType()); Element fieldElement = element.element(field.getName().toUpperCase()); if(fieldElement != null) { String value = fieldElement.getText(); Object fieldObj = basicType.getConstructor(String.class).newInstance(value); method.invoke(currentObj, fieldObj); } else { throw new Exception("parseXml Error. target:" + field.getName() + " is not exists"); } } else { if (isCollection(field.getType())) { //Collection解析 String getMethodStr = "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1); String setMethodStr = "set" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1); Method getMethod = c.getDeclaredMethod(getMethodStr); Collection collection = getCollectionByClass(field.getType()); Method setMethod = c.getDeclaredMethod(setMethodStr, field.getType()); setMethod.invoke(currentObj, collection); //正式返回類型的type對象。例如:java.util.List<com.bayern.xml.example.entity.req.StaffBindReqBody$Staffs> Type returnType = getMethod.getGenericReturnType(); //ParameterizedType : Comparable<? super T> , Collection符合該類型格式,例如Collection<String>。 if (returnType instanceof ParameterizedType) { ParameterizedType t = (ParameterizedType) returnType; //getActualTypeArguments():返回表示此類型實際類型參數的 Type 對象的數組。 //由於List、Set泛型中只有一個參數,因此直接經過[0]獲取。 Type pType = t.getActualTypeArguments()[0]; //Collection的泛型對象 Class pc = Class.forName(((Class) pType).getName()); Method addMethod = field.getType().getDeclaredMethod("add", Object.class); List<Element> elementList = element.elements(field.getName().toUpperCase()); for(Element pcElement : elementList) { Object parameterObj = pc.newInstance(); addMethod.invoke(collection, new Object[]{parameterObj}); parseXml(pc, parameterObj, true, pcElement); } } } else { //對象解析 parseXml(field.getType(), currentObj, false, currentElement); } } } return currentObj; }
bean ——>XML app
/** * 封裝xml * @param c 目標對象Class類 * @param currentObj 被轉換對象 * @param flag 是否須要xml頭及root標籤 * @return 解析後的xml * @throws Exception * @throws NoSuchMethodException */ @SuppressWarnings({ "unchecked", "rawtypes" }) public static String packageXml(Class c, Object currentObj, boolean flag) throws Exception { if(currentObj == null) { return ""; } StringBuffer xml = new StringBuffer(); if(flag) { xml.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); String[] strs = c.getName().split("\\."); xml.append("<").append(strs[strs.length-1].toUpperCase()).append(">"); } Field[] fieldArray = c.getDeclaredFields(); for(Field field : fieldArray) { if(field.isAnnotationPresent(XmlTransformAnnotation.class)) { XmlTransformAnnotation xmlAnnotation = field.getAnnotation(XmlTransformAnnotation.class); if(XmlTransformAnnotation.FLASE.equals(xmlAnnotation.value())) { continue; } } Class basicType = getBasicType(field.getType()); if (basicType != null) { //分裝基本類型(包括:String、Integer、Byte、Short、Long、Float、Double、Character、Boolean、int、byte、short、long、float、double、char、boolean) xml.append("<").append(field.getName().toUpperCase()).append(">"); String setMethod = "get" + field.getName().substring(0,1).toUpperCase() + field.getName().substring(1); Method method = c.getDeclaredMethod(setMethod); String value = method.invoke(currentObj) != null ? method.invoke(currentObj).toString() : ""; xml.append(value); xml.append("</").append(field.getName().toUpperCase()).append(">"); } else { if (isCollection(field.getType())) { //分裝Collection String getMethod = "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1); Method method = c.getDeclaredMethod(getMethod); Object collectionObj = method.invoke(currentObj); Type returnType = method.getGenericReturnType(); if (returnType instanceof ParameterizedType) { ParameterizedType t = (ParameterizedType) returnType; Type pType = t.getActualTypeArguments()[0]; Class pc = Class.forName(((Class) pType).getName()); Collection collection = (Collection)collectionObj; if(collection != null) { for(Iterator iter = collection.iterator(); iter.hasNext();) { Object subObj = iter.next(); xml.append("<").append(field.getName().toUpperCase()).append(">"); String subXml = packageXml(pc, subObj, false); xml.append(subXml); xml.append("</").append(field.getName().toUpperCase()).append(">"); } } } } else { //分裝對象 String[] strs = field.getName().split("\\."); strs = strs[strs.length - 1].split("\\$"); String className = strs[strs.length - 1]; xml.append("<").append(className.toUpperCase()).append(">"); String getMethod = "get" + className.substring(0, 1).toUpperCase() + className.substring(1); Method method = c.getDeclaredMethod(getMethod); Object subObj = method.invoke(currentObj); String subXml = packageXml(field.getType(), subObj, false); xml.append(subXml); xml.append("</").append(className.toUpperCase()).append(">"); } } } if(flag) { String[] strs = c.getName().split("\\."); xml.append("</").append(strs[strs.length-1].toUpperCase()).append(">"); } return xml.toString(); }
輔助方法 spa
/** * 判斷Class的類型是否是基本類型。基本類型包括:String、Integer、Byte、Short、Long、Float、Double、Character、Boolean、int、byte、short、long、float、double、char、boolean * 若是是基本類型則返回對應的Class,不然返回null * @param type * @return */ @SuppressWarnings("rawtypes") private static Class getBasicType(Class type) { if (String.class.equals(type)) { return String.class; } else if (Integer.class.equals(type)) { return Integer.class; } else if (Byte.class.equals(type)) { return Byte.class; } else if (Short.class.equals(type)) { return Short.class; } else if (Long.class.equals(type)) { return Long.class; } else if (Float.class.equals(type)) { return Float.class; } else if (Double.class.equals(type)) { return Double.class; } else if (Character.class.equals(type)) { return Character.class; } else if (Boolean.class.equals(type)) { return Boolean.class; } else if(type.getName().equals(Constant.BASIC_TYPE_BOOLEAN)) { return Boolean.class; } else if(type.getName().equals(Constant.BASIC_TYPE_BYTE)) { return Byte.class; } else if(type.getName().equals(Constant.BASIC_TYPE_CHAR)) { return Character.class; } else if(type.getName().equals(Constant.BASIC_TYPE_DOUBLE)) { return Double.class; } else if(type.getName().equals(Constant.BASIC_TYPE_FLOAT)) { return Float.class; } else if(type.getName().equals(Constant.BASIC_TYPE_INT)) { return Integer.class; } else if(type.getName().equals(Constant.BASIC_TYPE_SHORT)) { return Short.class; } return null; } /** * 判斷Class是否是Collection類型,這裏之判斷了List、Set兩種 * @param type * @return * @throws Exception */ @SuppressWarnings("rawtypes") private static boolean isCollection(Class type) throws Exception { //isAssignableFrom(Class<?> cls)斷定此 Class 對象所表示的類或接口與指定的 Class 參數所表示的類或接口是否相同,或是不是其超類或超接口。 if(List.class.isAssignableFrom(type)) { return true; } else if(Set.class.isAssignableFrom(type)) { return true; } return false; } /** * 根據class獲取Collection * @param type Collection對應的Class * @return * @throws Exception */ @SuppressWarnings("rawtypes") private static Collection getCollectionByClass(Class type) throws Exception { Collection collection = null; if(type.isInterface()) { List list = new ArrayList(); Set set = new HashSet(); //isInstance(Object obj)斷定指定的 Object 是否與此 Class 所表示的對象賦值兼容。 if (type.isInstance(list)) { collection = list; } else if(type.isInstance(set)) { collection = set; } }else { collection = (Collection)type.newInstance(); } return collection; }
完整代碼連接:https://git.oschina.net/bayern.com/XmlTransformFrame.git .net