摘要:當前對象,需要搜索查詢字段所屬的父類對象查詢字段所屬字段的父類對象類型查詢字段名稱此處異常捕獲為找不到屬性名異常。通過路徑以及包名,獲取所有類。自定義注解名稱。
Reflect 通過反射獲取自定義注解值給另外一個對象賦值
-
一、大致介紹1、今天剛完成這么一個功能模塊,需求場景是這樣的,我們需要對接許多銀行的接口,我們解析銀行XML報文后,根據每個銀行每個接口我們會解析得到很多BankDTO; 2、然后我們需要在BankDTO挑出一些必要的字段放到另外一個 ResultDTO 中去,然后將 ResultDTO 的數據入庫處理; 3、而且最關鍵的是,每個銀行的字段五花八門,我們根本沒辦法統一字段,最初的辦法我們是對每個 BankDTO 寫了一個轉換類轉成 ResultDTO; 4、但是隨著接入的銀行越來越多了,開發效率也就慢慢的降下來了,然而我就在思考如何優化這個字段轉換來轉換去的笨重方法; 5、經過輾轉反側的思考,最終自己定義一個注解類,然后將這些注解安插在BankDTO上,而我們需要做的事情就是反射獲取注解值然后給ResultDTO賦值即可; 6、原理就是這么簡單,這樣寫好之后,銀行一多,開發人員不夠,我們找些不會開發的人員只要告訴他們如何寫 BankDTO 對象即可,如何映射字段值即可,最后提交代碼就搞定了; 7、而我在這里主要將一些類貼出來僅供大家參考,如果這種思路在大家工作中用得著的話,相信稍微復用我這思路,功能很快就能水到渠成;二、實現步驟 2.1 反射工具類,參考網上代碼做了稍微調整,整理成符合自己業務邏輯的公用工具類
package com.springms.cloud.reflect.util; import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Enumeration; import java.util.List; /** * 反射工具類。 * * @author hmilyylimh * * @version 0.0.1 * * @date 2017/10/24 */ public class ReflectionUtil { private static final org.slf4j.Logger Logger = LoggerFactory.getLogger(ReflectionUtil.class); /** * 循環向上轉型, 獲取對象的 DeclaredField。 * * @param object : 子類對象,也就是實現類對象; * @param fieldName : 父類中的屬性名; * @return 父類中的屬性對象 */ public static Field getDeclaredField(Object object, String fieldName) { Field field = null; Class> clazz = object.getClass(); for (; clazz != Object.class; clazz = clazz.getSuperclass()) { try { field = clazz.getDeclaredField(fieldName); return field; } catch (Exception e) { // 這里甚么都不要做!并且這里的異常必須這樣寫,不能拋出去。 // 如果這里的異常打印或者往外拋,則就不會執行clazz = clazz.getSuperclass(),最后就不會進入到父類中了 // Logger.error("循環向上轉型, 獲取對象的 DeclaredField 異常, fieldName: {}, object: {}, e: {}", fieldName, object, CommonUtil.getExceptionStackTrace(e)); } } return null; } /** * 循環向上轉型, 獲取當前對象以及父類所有對象的屬性 Field 字段。 * * @param objectClass * @return */ public static List2.2 自定義注解類,主要用來安插在銀行響應類BankDTO身上的;getDeclaredSuperFields(Class> objectClass) { List declaredFieldList = new ArrayList (); Class> tempClass = objectClass; try { while(true){ if(tempClass == Object.class){ break; } declaredFieldList.addAll(Arrays.asList(tempClass.getDeclaredFields())); tempClass = tempClass.getSuperclass(); } } catch (Exception e) { // 這里甚么都不要做!并且這里的異常必須這樣寫,不能拋出去。 // 如果這里的異常打印或者往外拋,則就不會執行clazz = clazz.getSuperclass(),最后就不會進入到父類中了 Logger.error("循環向上轉型, 獲取當前對象以及父類所有對象的屬性 Field 字段異常, objectClass: {}, e: {}", objectClass, e); } return declaredFieldList; } /** * 循環向上轉型, 獲取對象的 DeclaredMethod。 * * @param object : 子類對象,也就是實現類對象; * @param methodName : 父類中的方法名; * @param parameterTypes : 父類中的方法參數類型; * @return 父類中的方法對象 */ public static Method getDeclaredMethod(Object object, String methodName, Class>... parameterTypes) { Method method = null; for (Class> clazz = object.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) { try { method = clazz.getDeclaredMethod(methodName, parameterTypes); return method; } catch (Exception e) { // 這里甚么都不要做!并且這里的異常必須這樣寫,不能拋出去。 // 如果這里的異常打印或者往外拋,則就不會執行clazz = clazz.getSuperclass(),最后就不會進入到父類中了 // Logger.error("循環向上轉型, 獲取對象的 DeclaredMethod 異常, methodName: {}, object: {}, parameterTypes: {}, e: {}", methodName, object, parameterTypes, CommonUtil.getExceptionStackTrace(e)); } } return null; } /** * 獲取 Field 字段的值。 * * @param field * @param fieldParentObj * @return */ public static Object getFieldValue(Field field, Object fieldParentObj) { Object value = null; try { field.setAccessible(true); value = field.get(fieldParentObj); } catch (Exception e) { Logger.error("獲取 Field 字段的值異常, field: {}, fieldParentObj: {}, e: {}", field, fieldParentObj, e); } return value; } /** * 設置 Field 字段的值。 * * @param field * @param fieldParentObj * @param newValueObj */ public static void setFieldValue(Field field, Object fieldParentObj, Object newValueObj) { try { field.setAccessible(true); field.set(fieldParentObj, newValueObj); } catch (Exception e) { Logger.error("設置 Field 字段的值異常, field: {}, fieldParentObj: {}, newValueObj: {}, e: {}", field, fieldParentObj, newValueObj, e); } } /** * 獲取當前對象中子對象的屬性。 * * @param parentObj:當前對象,需要搜索查詢字段所屬的父類對象; * @param searchFieldParentClass:查詢字段所屬字段的父類對象Class類型; * @param searchFieldName:查詢字段名稱; * @return new Object[] { searchFieldParentObject, searchField, searchFieldValue } */ public static Object[] getChildAttr(Object parentObj, Class> searchFieldParentClass, String searchFieldName) { if (parentObj == null) { return null; } Class> parentObjClass = parentObj.getClass(); Field foundedField = null; Object foundedFieldValue = null; Object[] result = null; try { foundedField = parentObjClass.getDeclaredField(searchFieldName); foundedField.setAccessible(true); foundedFieldValue = foundedField.get(parentObj); return new Object[]{parentObj, foundedField, foundedFieldValue}; } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { // 此處異常捕獲為:找不到屬性名異常。 // 注意在此處我們要手工去幫它找到field應該對象到哪個對象里的值,因為我們不知道它們之間的關系,所以需要手工指定關系,找哪個對象去關聯 result = getChildObjAttr(parentObj, parentObjClass, searchFieldParentClass, searchFieldName); } catch (IllegalArgumentException e) { Logger.error("獲取當前對象中子對象的屬性異常, searchFieldParentClass: {}, searchFieldName: {}, parentObj: {}, e: " + "{}", searchFieldParentClass, searchFieldName, parentObj, e); } catch (IllegalAccessException e) { Logger.error("獲取當前對象中子對象的屬性異常, searchFieldParentClass: {}, searchFieldName: {}, parentObj: {}, e: " + "{}", searchFieldParentClass, searchFieldName, parentObj, e); } return result; } /** * 獲取 parentObj 對象中子類對象的屬性。 * * @param parentObj:當前對象,需要搜索查詢字段所屬的父類對象; * @param parentObjClass:當前對象類名稱類型,需要搜索查詢字段所屬的父類類名稱類型; * @param searchFieldParentClass:查詢字段所屬字段的父類對象Class類型; * @param searchFieldName:查詢字段名稱; * @return new Object[] { searchFieldParentObject, searchField, searchFieldValue } */ private static Object[] getChildObjAttr(Object parentObj, Class> parentObjClass, Class> searchFieldParentClass, String searchFieldName) { Field[] childFields = parentObjClass.getDeclaredFields(); Field childField = null; Class> childFieldType = null; for (int i = 0; i < childFields.length; i++) { childField = childFields[i]; childFieldType = childField.getType(); if (!childFieldType.isMemberClass()) { if (childFieldType.equals(searchFieldParentClass)) { return getChildObjAttrDetail(parentObj, childField, searchFieldName); } } else { return getChildAttr(getFieldValue(childField, parentObj), searchFieldParentClass, searchFieldName); } } return null; } /** * 獲取 parentObj 對象中子類對象的明細屬性。 * * @param parentObj:當前對象,需要搜索查詢字段所屬的父類對象; * @param parentObjChildField:當前對象子對象,需要搜索查詢字段所屬的父類對象的子對象; * @param searchFieldName:查詢字段名稱; * @return new Object[] { searchFieldParentObject, searchField, searchFieldValue } */ private static Object[] getChildObjAttrDetail(Object parentObj, Field parentObjChildField, String searchFieldName) { parentObjChildField.setAccessible(true); Object searchFieldParentObject = null; Class> childClass = null; Field searchField = null; Object searchFieldValue = null; try { searchFieldParentObject = parentObjChildField.get(parentObj); childClass = searchFieldParentObject.getClass(); searchField = childClass.getDeclaredField(searchFieldName); searchField.setAccessible(true); searchFieldValue = searchField.get(searchFieldParentObject); return new Object[]{searchFieldParentObject, searchField, searchFieldValue}; } catch (IllegalArgumentException e) { Logger.error("獲取 parentObj 對象中子類對象的明細屬性異常, searchFieldName: {}, parentObj: {}, parentObjChildField: {}, " + " e: " + "{}", searchFieldName, parentObj, parentObjChildField, e); } catch (SecurityException e) { Logger.error("獲取 parentObj 對象中子類對象的明細屬性異常, searchFieldName: {}, parentObj: {}, parentObjChildField: {}, " + " e: " + "{}", searchFieldName, parentObj, parentObjChildField, e); } catch (IllegalAccessException e) { Logger.error("獲取 parentObj 對象中子類對象的明細屬性異常, searchFieldName: {}, parentObj: {}, parentObjChildField: {}, " + " e: " + "{}", searchFieldName, parentObj, parentObjChildField, e); } catch (NoSuchFieldException e) { Logger.error("獲取 parentObj 對象中子類對象的明細屬性異常, searchFieldName: {}, parentObj: {}, parentObjChildField: {}, " + " e: " + "{}", searchFieldName, parentObj, parentObjChildField, e); } return null; } /** * 獲取接口中所有實現類。 * * @param interfaceClass * @return */ public static List > getAllImplClasses(Class> interfaceClass) { if (!interfaceClass.isInterface()) { return null; } try { List > resultClassList = new ArrayList >(); // 獲得接口所在的當前包名 String packageName = interfaceClass.getPackage().getName(); // 獲取接口所在處的包名下的所有實現類 List > allClass = getClassesByPackageName(packageName); for (int i = 0; i < allClass.size(); i++) { if (interfaceClass.isAssignableFrom(allClass.get(i))) { if (!interfaceClass.equals(allClass.get(i))) {// 本身加不進去 resultClassList.add(allClass.get(i)); } } } return resultClassList; } catch (Exception e) { Logger.error("獲取接口中所有實現類異常, interfaceClass: {}, e: {}", interfaceClass, e); return null; } } /** * 通過包名獲取當前包名下所有的類。 * * @param packageName * @return * @throws IOException * @throws ClassNotFoundException */ private static List > getClassesByPackageName(String packageName) throws IOException, ClassNotFoundException { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); String path = packageName.replace(".", "/"); Enumeration resources = classLoader.getResources(path); List dirs = new ArrayList (); while (resources.hasMoreElements()) { URL resource = resources.nextElement(); dirs.add(new File(resource.getFile())); } List > resultClassList = new ArrayList >(); for (File directory : dirs) { resultClassList.addAll(findClasses(directory, packageName)); } return resultClassList; } /** * 通過路徑以及包名,獲取所有類。 * * @param directory * @param packageName * @return * @throws ClassNotFoundException */ private static List > findClasses(File directory, String packageName) throws ClassNotFoundException { List > resultClassList = new ArrayList >(); if (!directory.exists()) { return resultClassList; } File[] files = directory.listFiles(); for (File file : files) { if (file.isDirectory()) { assert !file.getName().contains("."); resultClassList.addAll(findClasses(file, packageName + "." + file.getName())); } else if (file.getName().endsWith(".class")) { resultClassList.add(Class.forName(packageName + "." + file.getName().substring(0, file.getName() .length() - 6))); } } return resultClassList; } }
package com.springms.cloud.reflect.util; import java.lang.annotation.*; /** * 成員字段注解(注解加在解析銀行返回的對象中)。 * * @author hmilyylimh * * @version 0.0.1 * * @date 2017/10/24 * */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface CustomFieldAnnotation { /** * 自定義注解名稱。 * * @return */ String customFieldName() default ""; /** * 自定義注解類型。 * * @return */ CustomFieldType customFieldType() default CustomFieldType.PRIMITIVE; /** * 標識字段是否有效。 * * @return */ boolean isEnable() default true; /** * 是否重新刷寫。 * * @return */ boolean isReWrite() default true; /** * 是否是子類屬性,是的話,則根據后面的子類所屬 Class 尋找字段屬性。 * * @return */ boolean isChild() default false; /** * 自定義注解類型 */ public static enum CustomFieldType { /** * 未知類型 */ Unknow, /** * 原生類型 */ PRIMITIVE, /** * 類成員類型 */ CLASS, /** * 數組類型 */ ARRAY, /** * 列表類型 */ LIST; public static CustomFieldType valueof(String fieldType) { if (CustomFieldType.PRIMITIVE.toString().equalsIgnoreCase(fieldType)) { return PRIMITIVE; } else if (CustomFieldType.CLASS.toString().equalsIgnoreCase(fieldType)) { return CLASS; } else if (CustomFieldType.ARRAY.toString().equalsIgnoreCase(fieldType)) { return ARRAY; } else if (CustomFieldType.LIST.toString().equalsIgnoreCase(fieldType)) { return LIST; } else { return Unknow; } } } }2.3 反射獲取注解值并給 ResultDTO 賦值的解析器類,非常非常重要的類
package com.springms.cloud.reflect.util; import org.apache.commons.lang3.StringUtils; import org.slf4j.LoggerFactory; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; /** * 注解反射解析器。 * * @author hmilyylimh * * @version 0.0.1 * * @date 2017/10/24 * */ public class AnnotationReflectParser { private static final org.slf4j.Logger Logger = LoggerFactory.getLogger(AnnotationReflectParser.class); /** * 開始解析。 * * @param bankObject:銀行報文對象。 * @param resultObject:解析后的通用對象。 */ public static boolean start(Object bankObject, Object resultObject) { try { convert(bankObject, resultObject); return true; } catch (Exception e) { Logger.error("開始解析出現最外層異常,bankObject: {}, resultObject: {}", bankObject, resultObject); return false; } } /** * 循環嵌套解析,該方法會被循環調用多次。 * * @param bankObject:銀行報文對象。 * @param resultObject:解析后的通用對象。 */ private static void convert(Object bankObject, Object resultObject) { if (bankObject == null) { Logger.error("循環嵌套解析,傳入 bankObject 為空, bankObject: {}, resultObject: {}", bankObject, resultObject); throw new RuntimeException("循環嵌套解析,傳入 bankObject 為空"); } if (resultObject == null) { Logger.error("循環嵌套解析,傳入 resultObject 為空, bankObject: {}, resultObject: {}", bankObject, resultObject); throw new RuntimeException("循環嵌套解析,傳入 resultObject 為空"); } Class> bankObjClass = bankObject.getClass(); List2.4 測試代碼,如何調用起我們寫的這套功能bankFields = ReflectionUtil.getDeclaredSuperFields(bankObjClass); if (bankFields == null || bankFields.isEmpty()) { Logger.error("循環嵌套解析,bankObject 對象內沒有 Field 屬性字段, bankObject: {}, resultObject: {}", bankObject, resultObject); return; } CustomFieldAnnotation customFieldAnnotation = null; CustomFieldAnnotation.CustomFieldType customFieldType = null; for (Field bankField : bankFields) { customFieldAnnotation = bankField.getAnnotation(CustomFieldAnnotation.class); // 過濾沒有注解的字段 if (customFieldAnnotation == null) { // Logger.error("循環嵌套解析,過濾沒有注解的字段, bankField: {}, bankObject: {}, resultObject: {}", bankField, bankObject, resultObject); continue; } // 過濾已經禁用的字段 if (!customFieldAnnotation.isEnable()) { Logger.error("循環嵌套解析,過濾已經禁用的字段, bankField: {}, bankObject: {}, resultObject: {}", bankField, bankObject, resultObject); continue; } // 過濾沒有定義類型的字段 customFieldType = customFieldAnnotation.customFieldType(); if (customFieldType == null || customFieldType == CustomFieldAnnotation.CustomFieldType.Unknow) { Logger.error("循環嵌套解析,過濾沒有定義類型的字段, bankField: {}, bankObject: {}, resultObject: {}", bankField, bankObject, resultObject); continue; } // 針對不同類型走不同分支處理 switch (customFieldType) { case PRIMITIVE: { setPrimitiveType(bankField, bankObject, customFieldAnnotation, resultObject); break; } case CLASS: { setClassType(bankField, bankObject, customFieldAnnotation, resultObject); break; } case ARRAY: { setArrayType(bankField, bankObject, customFieldAnnotation, resultObject); break; } case LIST: { setListType(bankField, bankObject, customFieldAnnotation, resultObject); break; } case Unknow: { String msg = String.format("循環嵌套解析, 走進了沒有邏輯處理的分支類型, customFieldName: %s, bankFieldName: %s", customFieldAnnotation.customFieldName(), bankField.getName()); Logger.error(msg); throw new RuntimeException(msg); } } } } /** * 設置基本類型字段。 * * @param bankField * @param bankFieldParentObj * @param customFieldAnnotation * @param resultObject */ private static void setPrimitiveType(Field bankField, Object bankFieldParentObj, CustomFieldAnnotation customFieldAnnotation, Object resultObject) { try { String customFieldName = customFieldAnnotation.customFieldName(); Object bankFieldValue = ReflectionUtil.getFieldValue(bankField, bankFieldParentObj); Object[] fieldMapping = AnnotationMapping.getGeneralFieldMapping().get(customFieldName); if (fieldMapping == null) { String msg = String.format("設置基本類型字段, 沒有設置通用字段映射關系, customFieldName: %s, bankFieldName: %s", customFieldName, bankField.getName()); Logger.error(msg); throw new RuntimeException(msg); } String commonMappingFieldName = (String) fieldMapping[0]; if (StringUtils.isEmpty(commonMappingFieldName)) { String msg = String.format("設置基本類型字段, 通用對象中的屬性字段為空, customFieldName: %s, bankFieldName: %s", customFieldName, bankField.getName()); Logger.error(msg); throw new RuntimeException(msg); } // 獲取 resultObject 結果對象中 commonMappingFieldName 字段對象 Field // 從 resultObject 當前對象找,以及從 resultObject 父類找 commonMappingFieldName 屬性字段 Field commonMappingField = ReflectionUtil.getDeclaredField(resultObject, commonMappingFieldName); Object fieldParentObj = resultObject; if (customFieldAnnotation.isChild() || commonMappingField == null) { // 如果找不到的話,那么則嘗試從 resultObject 對象的子對象遞歸子對象找 commonMappingFieldName 屬性字段 Class> commonMappingFieldSuperClass = (Class>) fieldMapping[1]; Object[] childAttr = ReflectionUtil.getChildAttr(resultObject, commonMappingFieldSuperClass, commonMappingFieldName); if (childAttr == null) { String msg = String.format("設置基本類型字段, 在通用對象的子類中沒有搜索到通用屬性字段, customFieldName: %s, bankFieldName: %s, " + "commonMappingFieldName: %s", customFieldName, bankField.getName(), commonMappingFieldName); Logger.error(msg); throw new RuntimeException(msg); } fieldParentObj = childAttr[0]; commonMappingField = (Field) childAttr[1]; } // 給結果對象 resultObject 賦值,類型對等則直接賦值 if (customFieldAnnotation.isReWrite()) { ReflectionUtil.setFieldValue(commonMappingField, fieldParentObj, bankFieldValue); } else if (commonMappingField.getType() == bankFieldValue.getClass()) { ReflectionUtil.setFieldValue(commonMappingField, fieldParentObj, bankFieldValue); } // 類型不對等的話,則記錄錯誤日志 else { Logger.error("設置基本類型字段, 類型不對等的話, 銀行字段名稱: {}, 通用對象字段名稱: {}, bankFieldParentObj: {}, customFieldAnnotation: {}, " + "resultObject: {}", bankField.getName(), customFieldAnnotation.customFieldName(), bankFieldParentObj, customFieldAnnotation, resultObject); } } catch (Exception e) { Logger.error("設置基本類型字段異常, 銀行字段名稱: {}, 通用對象字段名稱: {}, bankFieldParentObj: {}, customFieldAnnotation: {}, " + "resultObject: {}, e: " + "{}", bankField.getName(), customFieldAnnotation.customFieldName(), bankFieldParentObj, customFieldAnnotation, resultObject, e); throw new RuntimeException("設置基本類型字段異常"); } } /** * 設置類成員類型字段。 * * @param bankField * @param bankFieldParentObj * @param customFieldAnnotation * @param resultObject */ private static void setClassType(Field bankField, Object bankFieldParentObj, CustomFieldAnnotation customFieldAnnotation, Object resultObject) { try { String customFieldName = customFieldAnnotation.customFieldName(); Object bankFieldValue = ReflectionUtil.getFieldValue(bankField, bankFieldParentObj); if (bankFieldValue == null) { Logger.error("設置類成員類型字段,解析銀行對象中 {} 屬性字段值為空。", bankField.getName()); return; } Class> bankFieldObjClass = bankFieldValue.getClass(); Field[] bankFieldObjFields = bankFieldObjClass.getDeclaredFields(); if (bankFieldObjFields == null || bankFieldObjFields.length == 0) { Logger.error("設置類成員類型字段,bankField 對象內沒有 Field 屬性字段, bankFieldName: {}, bankFieldParentObj: {}, " + "customFieldAnnotation: {}, resultObject: {}, ", bankField.getName(), bankFieldParentObj, customFieldAnnotation, resultObject); return; } // resultObject 該對象有數據,那么就得在 resultObject 中實例化對應的對象 Object[] fieldMapping = AnnotationMapping.getGeneralFieldMapping().get(customFieldName); if (fieldMapping == null) { String msg = String.format("設置類成員類型字段, 沒有設置通用字段映射關系, customFieldName: %s, bankFieldName: %s", customFieldName, bankField.getName()); Logger.error(msg); throw new RuntimeException(msg); } String commonMappingFieldName = (String) fieldMapping[0]; if (StringUtils.isEmpty(commonMappingFieldName)) { String msg = String.format("設置類成員類型字段, 通用對象中的屬性字段為空, customFieldName: %s, bankFieldName: %s", customFieldName, bankField.getName()); Logger.error(msg); throw new RuntimeException(msg); } // 從 resultObject 當前對象找,以及從 resultObject 父類找 commonMappingFieldName 屬性字段 Field commonMappingField = ReflectionUtil.getDeclaredField(resultObject, commonMappingFieldName); Object fieldParentObj = resultObject; if (commonMappingField == null) { // 如果找不到的話,那么則嘗試從 resultObject 對象的子對象遞歸子對象找 commonMappingFieldName 屬性字段 Class> commonMappingFieldSuperClass = (Class>) fieldMapping[1]; Object[] childAttr = ReflectionUtil.getChildAttr(resultObject, commonMappingFieldSuperClass, commonMappingFieldName); if (childAttr == null) { String msg = String.format("設置類成員類型字段, 在通用對象的子類中沒有搜索到通用屬性字段, customFieldName: %s, bankFieldName: %s, " + "commonMappingFieldName: %s", customFieldName, bankField.getName(), commonMappingFieldName); Logger.error(msg); throw new RuntimeException(msg); } fieldParentObj = childAttr[0]; commonMappingField = (Field) childAttr[1]; } // 獲取 resultObject 結果對象中 Field 字段的值 if (ReflectionUtil.getFieldValue(commonMappingField, fieldParentObj) == null) { Object newInstance = commonMappingField.getType().newInstance(); ReflectionUtil.setFieldValue(commonMappingField, resultObject, newInstance); } convert(bankFieldValue, resultObject); } catch (Exception e) { Logger.error("設置類成員類型字段異常, bankField: {}, bankFieldParentObj: {}, customFieldAnnotation: {}, " + "resultObject: {}, e: " + "{}", bankField, bankFieldParentObj, customFieldAnnotation, resultObject, e); throw new RuntimeException("設置類成員類型字段異常"); } } /** * 設置數組類型字段。 * * @param bankField * @param bankFieldParentObj * @param customFieldAnnotation * @param resultObject */ private static void setArrayType(Field bankField, Object bankFieldParentObj, CustomFieldAnnotation customFieldAnnotation, Object resultObject) { try { String customFieldName = customFieldAnnotation.customFieldName(); Object bankFieldValue = ReflectionUtil.getFieldValue(bankField, bankFieldParentObj); if (bankFieldValue == null) { Logger.error("設置數組類型字段,解析銀行對象中 {} 屬性字段值為空。", bankField.getName()); return; } int length = Array.getLength(bankFieldValue); if (length <= 0) { String msg = String.format("設置數組類型字段, 銀行數組長度為空, customFieldName: %s, bankFieldName: %s", customFieldName, bankField.getName()); Logger.error(msg); return; } // resultObject 該對象有數據,那么就得在 resultObject 中實例化對應的對象 Object[] fieldMapping = AnnotationMapping.getGeneralFieldMapping().get(customFieldName); if (fieldMapping == null) { String msg = String.format("設置數組類型字段, 沒有設置通用字段映射關系, customFieldName: %s, bankFieldName: %s", customFieldName, bankField.getName()); Logger.error(msg); throw new RuntimeException(msg); } String commonMappingFieldName = (String) fieldMapping[0]; if (StringUtils.isEmpty(commonMappingFieldName)) { String msg = String.format("設置數組類型字段, 通用對象中的屬性字段為空, customFieldName: %s, bankFieldName: %s", customFieldName, bankField.getName()); Logger.error(msg); throw new RuntimeException(msg); } // 從 resultObject 當前對象找,以及從 resultObject 父類找 commonMappingFieldName 屬性字段 Field commonMappingField = ReflectionUtil.getDeclaredField(resultObject, commonMappingFieldName); Object fieldParentObj = resultObject; if (commonMappingField == null) { // 如果找不到的話,那么則嘗試從 resultObject 對象的子對象遞歸子對象找 commonMappingFieldName 屬性字段 Class> commonMappingFieldSuperClass = (Class>) fieldMapping[1]; Object[] childAttr = ReflectionUtil.getChildAttr(resultObject, commonMappingFieldSuperClass, commonMappingFieldName); if (childAttr == null) { String msg = String.format("設置數組類型字段, 在通用對象的子類中沒有搜索到通用屬性字段, customFieldName: %s, bankFieldName: %s, " + "commonMappingFieldName: %s", customFieldName, bankField.getName(), commonMappingFieldName); Logger.error(msg); throw new RuntimeException(msg); } fieldParentObj = childAttr[0]; commonMappingField = (Field) childAttr[1]; } // 獲取 resultObject 結果對象中 Field 字段的值 if (ReflectionUtil.getFieldValue(commonMappingField, fieldParentObj) == null) { Class> elementType = commonMappingField.getType(); String elementTypeName = elementType.getName(); int startIndex = elementTypeName.indexOf("com"); int endIndex = elementTypeName.lastIndexOf(";"); String innerClassName = elementTypeName.substring(startIndex, endIndex); Class> innerClass = Class.forName(innerClassName); // 實例化數組 Object newInstance = Array.newInstance(innerClass, length); // 數組賦值空對象 Object[] arrays = (Object[]) newInstance; Object[] bankFieldValueArrays = (Object[]) bankFieldValue; for (int i = 0; i < length; i++) { arrays[i] = innerClass.newInstance(); } // 將空數組賦值到 resultObject 結果對象中 ReflectionUtil.setFieldValue(commonMappingField, fieldParentObj, newInstance); // 循環解析 bankFieldValueArrays 的值放到結果對象中對應的索引位置中 for (int i = 0; i < length; i++) { Object itemResultObject = arrays[i]; convert(bankFieldValueArrays[i], itemResultObject); } } } catch (Exception e) { Logger.error("設置數組類型字段異常, bankField: {}, bankFieldParentObj: {}, customFieldAnnotation: {}, " + "resultObject: {}, e: " + "{}", bankField, bankFieldParentObj, customFieldAnnotation, resultObject, e); throw new RuntimeException("設置數組類型字段異常"); } } /** * 設置列表類型字段。 * * @param bankField * @param bankFieldParentObj * @param customFieldAnnotation * @param resultObject */ private static void setListType(Field bankField, Object bankFieldParentObj, CustomFieldAnnotation customFieldAnnotation, Object resultObject) { try { String customFieldName = customFieldAnnotation.customFieldName(); Object bankFieldValue = ReflectionUtil.getFieldValue(bankField, bankFieldParentObj); if (bankFieldValue == null) { Logger.error("設置列表類型字段,解析銀行對象中 {} 屬性字段值為空。", bankField.getName()); return; } List bankFieldValueList = (List) bankFieldValue; int size = bankFieldValueList.size(); if (size <= 0) { String msg = String.format("設置列表類型字段, 銀行列表長度為空, customFieldName: %s, bankFieldName: %s", customFieldName, bankField.getName()); Logger.error(msg); return; } // resultObject 該對象有數據,那么就得在 resultObject 中實例化對應的對象 Object[] fieldMapping = AnnotationMapping.getGeneralFieldMapping().get(customFieldName); if (fieldMapping == null) { String msg = String.format("設置列表類型字段, 沒有設置通用字段映射關系, customFieldName: %s, bankFieldName: %s", customFieldName, bankField.getName()); Logger.error(msg); throw new RuntimeException(msg); } String commonMappingFieldName = (String) fieldMapping[0]; if (StringUtils.isEmpty(commonMappingFieldName)) { String msg = String.format("設置列表類型字段, 通用對象中的屬性字段為空, customFieldName: %s, bankFieldName: %s", customFieldName, bankField.getName()); Logger.error(msg); throw new RuntimeException(msg); } // 從 resultObject 當前對象找,以及從 resultObject 父類找 commonMappingFieldName 屬性字段 Field commonMappingField = ReflectionUtil.getDeclaredField(resultObject, commonMappingFieldName); Object fieldParentObj = resultObject; if (commonMappingField == null) { // 如果找不到的話,那么則嘗試從 resultObject 對象的子對象遞歸子對象找 commonMappingFieldName 屬性字段 Class> commonMappingFieldSuperClass = (Class>) fieldMapping[1]; Object[] childAttr = ReflectionUtil.getChildAttr(resultObject, commonMappingFieldSuperClass, commonMappingFieldName); if (childAttr == null) { String msg = String.format("設置列表類型字段, 在通用對象的子類中沒有搜索到通用屬性字段, customFieldName: %s, bankFieldName: %s, " + "commonMappingFieldName: %s", customFieldName, bankField.getName(), commonMappingFieldName); Logger.error(msg); throw new RuntimeException(msg); } fieldParentObj = childAttr[0]; commonMappingField = (Field) childAttr[1]; } Type genericType = commonMappingField.getGenericType(); if(!(genericType instanceof ParameterizedType)){ String msg = String.format("設置列表類型字段, 通用對象中的屬性字段類型設置有誤,設置的不是列表類型, customFieldName: %s, bankFieldName: %s", customFieldName, bankField.getName()); Logger.error(msg); return; } // 獲取 resultObject 結果對象中 Field 字段的值 if (ReflectionUtil.getFieldValue(commonMappingField, fieldParentObj) == null) { ParameterizedType parameterizedType = (ParameterizedType)genericType; Class> innerClass = (Class) parameterizedType.getActualTypeArguments()[0];//得到對象list中實例的類型 // 實例化數組 List newInstance = new ArrayList(); // 數組賦值空對象 for (int i = 0; i < size; i++) { newInstance.add(innerClass.newInstance()); } // 將空數組賦值到 resultObject 結果對象中 ReflectionUtil.setFieldValue(commonMappingField, fieldParentObj, newInstance); // 循環解析 bankFieldValueArrays 的值放到結果對象中對應的索引位置中 for (int i = 0; i < size; i++) { Object itemResultObject = newInstance.get(i); convert(bankFieldValueList.get(i), itemResultObject); } } } catch (Exception e) { Logger.error("設置列表類型字段異常, bankField: {}, bankFieldParentObj: {}, customFieldAnnotation: {}, " + "resultObject: {}, e: " + "{}", bankField, bankFieldParentObj, customFieldAnnotation, resultObject, e); throw new RuntimeException("設置列表類型字段異常"); } } }
package com.springms.cloud.reflect; import com.springms.cloud.reflect.util.AnnotationReflectParser; import com.springms.cloud.reflect.util.xml.BeanXml; /** * 測試類。 * * @author hmilyylimh * * @version 0.0.1 * * @date 2017/10/24 * */ public class TestReflectDemo { public static void main(String[] args) { try { String xmlData = getXml(); Class> beanClass = getBeanClassPath(); Object respBankDTO = BeanXml.xml2Bean(xmlData, beanClass); ResultDTO resultObject = new ResultDTO(); ResultDTO.Record record = new ResultDTO.Record(); resultObject.setRecord(record); boolean finished = AnnotationReflectParser.start(respBankDTO, resultObject); System.out.println("finished: " + finished); System.out.println("====================================="); } catch (Exception e) { e.printStackTrace(); } } /** * 這里可以通過路徑反射得到 Class 類,如果你的類有規律的話,那完成可以在這個地方通過設定規則出來得到類名路徑。 * * 那么我這里呢,就直接拿個例子來試試而已。 * * @return */ private static Class> getBeanClassPath() { String className = "com.springms.cloud.reflect.BankDTO"; return getRespBeanClass(className); } private static String getXml() { String recvContent = " " + "2.5 總結" + " " + " "; return recvContent; } /** * 獲取響應類名的 Class 對象。 * * @return */ private static Class> getRespBeanClass(String className) { Class> respClass = null; try { respClass = Class.forName(className); return respClass; } catch (ClassNotFoundException e) { throw new RuntimeException(className + " 該響應類路徑不存在", e); } } }4469 " + "0 " + "1234567890 " + "2004-07-28 16:14:29 " + "AAAAAAA " + " " + " " + "246333388999 " + "張三 " + "199098777.97 " + "199098777.97 " + "" + " " + " " + "" + "
" + "1234567890000000 " + "234.56 " + "賬戶名稱甲 " + "
1、雖然這樣寫可以偷懶了,也可以招非開發人員直接上手擼代碼直接開發功能模塊,但是不方便的地方就是得發版升級; 2、后期想法,我們不是有 "Java運行時動態加載類" 這么一說么?后期準備將這一套代碼放在某個目錄上傳,或者直接放到數據庫存儲,然后動態加載執行對應功能; 3、想法雖然不錯,路漫漫其修遠兮,慢慢努力吧,順便祝各位猿猿們節日快樂;三、下載地址
https://git.oschina.net/ylimhhmily/SpringCloudTutorial.git
SpringCloudTutorial交流QQ群: 235322432
SpringCloudTutorial交流微信群: 微信溝通群二維碼圖片鏈接
歡迎關注,您的肯定是對我最大的支持!!!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/67858.html
摘要:當前對象,需要搜索查詢字段所屬的父類對象查詢字段所屬字段的父類對象類型查詢字段名稱此處異常捕獲為找不到屬性名異常。通過路徑以及包名,獲取所有類。自定義注解名稱。 Reflect 通過反射獲取自定義注解值給另外一個對象賦值 - 一、大致介紹 1、今天剛完成這么一個功能模塊,需求場景是這樣的,我們需要對接許多銀行的接口,我們解析銀行XML報文后,根據每個銀行每個接口我們會解析得到很多Ban...
摘要:第章元編程與注解反射反射是在運行時獲取類的函數方法屬性父類接口注解元數據泛型信息等類的內部信息的機制。本章介紹中的注解與反射編程的相關內容。元編程本質上是一種對源代碼本身進行高層次抽象的編碼技術。反射是促進元編程的一種很有價值的語言特性。 第12章 元編程與注解、反射 反射(Reflection)是在運行時獲取類的函數(方法)、屬性、父類、接口、注解元數據、泛型信息等類的內部信息的機...
摘要:前言注解就是提供了一種元程序中的元素關聯任何信息和著任何元數據的途徑和方法。注解是一個接口,程序可以通過反射來獲取指定程序元素的對象,然后通過對象來獲取注解里面的元數據。注解是及以后版本引入的。綜上所述元數據以標簽的形式存在于代碼中。 前言 Annotation(注解)就是Java提供了一種元程序中的元素關聯任何信息和著任何元數據(metadata)的途徑和方法。Annotion(注解...
摘要:注解提供了一種安全的類似注釋的機制,用來將任何的信息或元數據與程序元素類方法成員變量等進行關聯。為程序的元素類方法成員變量加上更直觀更明了的說明,這些說明與程序的業務邏輯無關,并且提供給指定的工具或框架使用。 什么是注解? Annotation 是 Java5 之后開始引入的新特性,中文為注解。注解提供了一種安全的類似注釋的機制,用來將任何的信息或元數據(metadata)與程序元素(...
閱讀 2902·2023-04-26 02:14
閱讀 3751·2019-08-30 15:55
閱讀 1843·2019-08-29 16:42
閱讀 2757·2019-08-26 11:55
閱讀 2846·2019-08-23 13:38
閱讀 480·2019-08-23 12:10
閱讀 1308·2019-08-23 11:44
閱讀 2790·2019-08-23 11:43