Reflect 通過反射獲取自定義註解值給另外一個對象賦值

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: {}, \n\ne: {}", fieldName, object, CommonUtil.getExceptionStackTrace(e));
            }
        }

        return null;
    }

    /**
     * 循環向上轉型, 獲取當前對象以及父類所有對象的屬性 Field 字段。
     *
     * @param objectClass
     * @return
     */
    public static List<Field> getDeclaredSuperFields(Class<?> objectClass) {
        List<Field> declaredFieldList = new ArrayList<Field>();

        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: {}, \n\ne: {}", 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: {}, \n\ne: {}", 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: {}, \n\ne: {}", 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: {}, \n\ne: {}", 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: {}, \n\ne: " +
                            "{}", searchFieldParentClass, searchFieldName,
                    parentObj, e);
        } catch (IllegalAccessException e) {
            Logger.error("獲取當前對象中子對象的屬性異常, searchFieldParentClass: {}, searchFieldName: {}, parentObj: {}, \n\ne: " +
                            "{}", 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: {}, " +
                    "\n\ne: " +
                    "{}", searchFieldName, parentObj, parentObjChildField, e);
        } catch (SecurityException e) {
            Logger.error("獲取 parentObj 對象中子類對象的明細屬性異常, searchFieldName: {}, parentObj: {}, parentObjChildField: {}, " +
                    "\n\ne: " +
                    "{}", searchFieldName, parentObj, parentObjChildField, e);
        } catch (IllegalAccessException e) {
            Logger.error("獲取 parentObj 對象中子類對象的明細屬性異常, searchFieldName: {}, parentObj: {}, parentObjChildField: {}, " +
                    "\n\ne: " +
                    "{}", searchFieldName, parentObj, parentObjChildField, e);
        } catch (NoSuchFieldException e) {
            Logger.error("獲取 parentObj 對象中子類對象的明細屬性異常, searchFieldName: {}, parentObj: {}, parentObjChildField: {}, " +
                    "\n\ne: " +
                    "{}", searchFieldName, parentObj, parentObjChildField, e);
        }

        return null;
    }

    /**
     * 獲取接口中所有實現類。
     *
     * @param interfaceClass
     * @return
     */
    public static List<Class<?>> getAllImplClasses(Class<?> interfaceClass) {
        if (!interfaceClass.isInterface()) {
            return null;
        }

        try {
            List<Class<?>> resultClassList = new ArrayList<Class<?>>();

            // 獲得接口所在的當前包名
            String packageName = interfaceClass.getPackage().getName();

            // 獲取接口所在處的包名下的所有實現類
            List<Class<?>> 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: {}, \n\ne: {}", interfaceClass, e);
            return null;
        }
    }

    /**
     * 通過包名獲取當前包名下所有的類。
     *
     * @param packageName
     * @return
     * @throws IOException
     * @throws ClassNotFoundException
     */
    private static List<Class<?>> getClassesByPackageName(String packageName) throws IOException,
            ClassNotFoundException {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        String path = packageName.replace('.', '/');
        Enumeration<URL> resources = classLoader.getResources(path);
        List<File> dirs = new ArrayList<File>();
        while (resources.hasMoreElements()) {
            URL resource = resources.nextElement();
            dirs.add(new File(resource.getFile()));
        }
        List<Class<?>> resultClassList = new ArrayList<Class<?>>();
        for (File directory : dirs) {
            resultClassList.addAll(findClasses(directory, packageName));
        }
        return resultClassList;
    }

    /**
     * 通過路徑以及包名,獲取所有類。
     *
     * @param directory
     * @param packageName
     * @return
     * @throws ClassNotFoundException
     */
    private static List<Class<?>> findClasses(File directory, String packageName) throws ClassNotFoundException {
        List<Class<?>> resultClassList = new ArrayList<Class<?>>();
        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;
    }
}

2.2 自定義註解類,主要用來安插在銀行響應類BankDTO身上的;

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();
        List<Field> 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: {}, \n\ne: " +
                    "{}", 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: {}, \n\ne: " +
                    "{}", 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: {}, \n\ne: " +
                    "{}", 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: {}, \n\ne: " +
                    "{}", bankField, bankFieldParentObj, customFieldAnnotation, resultObject, e);
            throw new RuntimeException("設置列表類型字段異常");
        }
    }
}

2.4 測試代碼,如何調用起我們寫的這套功能

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 = "<?xml version='1.0' encoding='GB2312'?>\n" +
                "<packet>\n" +
                "<head>\n" +
                "<transCode>4469</transCode>  \n" +
                "<signFlag>0</signFlag>   \n" +
                "<packetID>1234567890</packetID>      \n" +
                "<timeStamp>2004-07-28 16:14:29</timeStamp> \n" +
                "<returnCode>AAAAAAA</returnCode>  \n" +
                "</head>\n" +
                "<body>\n" +
                "<acctNo>246333388999</acctNo>\n" +
                "<acctName>張三</acctName>\n" +
                "<acctBalance>199098777.97</acctBalance>\n" +
                "<subTotBalance>199098777.97</subTotBalance>\n" +
                "<lists name=\"LoopResult\">\n" +
                "<list>\n" +
                "<subAcctNo>1234567890000000</subAcctNo>\n" +
                "<subAcctBalance>234.56</subAcctBalance>\n" +
                "<subAcctName>賬戶名稱甲</subAcctName>\n" +
                "</list>\n" +
                "</lists>\n" +
                "</body>\n" +
                "</packet>";

        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);
        }
    }
}

2.5 總結

1、雖然這樣寫可以偷懶了,也可以招非開發人員直接上手擼代碼直接開發功能模塊,但是不方便的地方就是得發版升級;
2、後期想法,我們不是有 "Java運行時動態加載類" 這麼一說麼?後期準備將這一套代碼放在某個目錄上傳,或者直接放到數據庫存儲,然後動態加載執行對應功能;
3、想法雖然不錯,路漫漫其修遠兮,慢慢努力吧,順便祝各位猿猿們節日快樂;

三、下載地址

https://git.oschina.net/ylimhhmily/SpringCloudTutorial.git

SpringCloudTutorial交流QQ羣: 235322432

SpringCloudTutorial交流微信羣: 微信溝通羣二維碼圖片鏈接

歡迎關注,您的肯定是對我最大的支持!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章