资讯专栏INFORMATION COLUMN

Reflect 通过反射获取自定义注解值给另外一个对象赋值

岳光 / 2882人阅读

摘要:当前对象,需要搜索查询字段所属的父类对象查询字段所属字段的父类对象类型查询字段名称此处异常捕获为找不到属性名异常。通过路径以及包名,获取所有类。自定义注解名称。

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 List 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;
    }
}
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 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("设置列表类型字段异常");
        }
    }
}
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 = "
" +
                "
" +
                "
" +
                "4469  
" +
                "0   
" +
                "1234567890      
" +
                "2004-07-28 16:14:29 
" +
                "AAAAAAA  
" +
                "
" +
                "
" +
                "246333388999
" +
                "张三
" +
                "199098777.97
" +
                "199098777.97
" +
                "
" +
                "
" +
                "1234567890000000
" +
                "234.56
" +
                "账户名称甲
" +
                "
" +
                "
" +
                "
" +
                "";

        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交流微信群: 微信沟通群二维码图片链接

欢迎关注,您的肯定是对我最大的支持!!!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/67858.html

相关文章

  • Reflect 通过反射获取定义注解值给另外一个对象赋值

    摘要:当前对象,需要搜索查询字段所属的父类对象查询字段所属字段的父类对象类型查询字段名称此处异常捕获为找不到属性名异常。通过路径以及包名,获取所有类。自定义注解名称。 Reflect 通过反射获取自定义注解值给另外一个对象赋值 - 一、大致介绍 1、今天刚完成这么一个功能模块,需求场景是这样的,我们需要对接许多银行的接口,我们解析银行XML报文后,根据每个银行每个接口我们会解析得到很多Ban...

    silvertheo 评论0 收藏0
  • 第12章 元编程与注解反射 《Kotlin 项目实战开发》

    摘要:第章元编程与注解反射反射是在运行时获取类的函数方法属性父类接口注解元数据泛型信息等类的内部信息的机制。本章介绍中的注解与反射编程的相关内容。元编程本质上是一种对源代码本身进行高层次抽象的编码技术。反射是促进元编程的一种很有价值的语言特性。 第12章 元编程与注解、反射 反射(Reflection)是在运行时获取类的函数(方法)、属性、父类、接口、注解元数据、泛型信息等类的内部信息的机...

    joyqi 评论0 收藏0
  • 聊聊Java的注解及实现

    摘要:前言注解就是提供了一种元程序中的元素关联任何信息和着任何元数据的途径和方法。注解是一个接口,程序可以通过反射来获取指定程序元素的对象,然后通过对象来获取注解里面的元数据。注解是及以后版本引入的。综上所述元数据以标签的形式存在于代码中。 前言 Annotation(注解)就是Java提供了一种元程序中的元素关联任何信息和着任何元数据(metadata)的途径和方法。Annotion(注解...

    The question 评论0 收藏0
  • 注解就这么简单

    摘要:上面在将注解信息注入到方法中的时候,我们最后加上了的注解不然就会报错了那它是干什么用的呢只能用于修饰其他的,用于指定被修饰的被保留多长时间。 前言 今天要讲的是注解,对于本章节,最好是有Servlet基础的人查阅~因为单纯是Java基础的话,可能用不上注解这个东西。但如果开发过Servlet,就对@WebServlet不会陌生。 现在的开发都推崇使用注解来进行开发,这样就可以免去写XM...

    FrozenMap 评论0 收藏0
  • Java基础知识整理之注解

    摘要:注解提供了一种安全的类似注释的机制,用来将任何的信息或元数据与程序元素类方法成员变量等进行关联。为程序的元素类方法成员变量加上更直观更明了的说明,这些说明与程序的业务逻辑无关,并且提供给指定的工具或框架使用。 什么是注解? Annotation 是 Java5 之后开始引入的新特性,中文为注解。注解提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(...

    blastz 评论0 收藏0

发表评论

0条评论

岳光

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<