通过反射拷贝不同泛型的集合

        上个项目有个集合拷贝的工具,用过但没细看怎么实现的,今天突然想起来就按自己的思路写一个,写到一半发现网上有更好的办法,直接把集合转 JsonArray ,再转成自己想要的类型的集合即可,写了一两个小时也不想删了,目前支持拷贝自己和父类非 final 修饰的字段,还不支持 List<A> A里还包个B类的情况。

    /**
     * 反射copy集合 List<A> -> List<B>  字段名,类型相同就copy
     * @param resources
     * @param clz
     * @param <T>
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws IntrospectionException
     * @throws InvocationTargetException
     */
    private static <T> List<T> copyCollection(List<?> resources, Class<T> clz) throws InstantiationException, IllegalAccessException, IntrospectionException, InvocationTargetException {
        assert !CollectionUtils.isEmpty(resources);
        List<T> result = new ArrayList<>();
        T single;
        // 获取源集合泛型的class
        Class<?> sourceClass = resources.get(0).getClass();
        List<Field> sourceFields = new ArrayList<>();
        // 递归获取自己和父类的字段
        sourceFields = getSuperField(sourceClass, sourceFields);
        // 获取目标类型的字段
        List<Field> targetFields = new ArrayList<>();
        targetFields = getSuperField(clz, targetFields);
        // 转成 key 是字段名, value 是字段类型的 map,方便校验
        Map<String, ? extends Class<?>> fieldNameTypeMap = targetFields.stream().collect(Collectors.toMap(Field::getName, Field::getType));

        PropertyDescriptor propertyDescriptor;
        for (Object resource : resources) {
            // 实例化目标类型
            single = clz.newInstance();
            for (Field declaredField : sourceFields) {
                declaredField.setAccessible(true);
                String fieldName = declaredField.getName();
                // 字段不被 finla 修饰,并且目标类包含此字段,并且字段类型一致才能继续走逻辑
                if (Modifier.isFinal(declaredField.getModifiers())
                        || !fieldNameTypeMap.containsKey(fieldName)
                        || !fieldNameTypeMap.get(fieldName).equals(declaredField.getType())) {
                    continue;
                }
                // 获取字段值
                Object value = declaredField.get(resource);
                // 获取字段的 set 方法,并设置值
                propertyDescriptor = new PropertyDescriptor(fieldName, clz);
                propertyDescriptor.getWriteMethod().invoke(single, value);
            }
            result.add(single);
        }

        return result;
    }

    /**
     * 递归获取自己和父类的全部字段,包括父类的父类
     * @param clz
     * @param result
     * @return
     */
    private static List<Field> getSuperField(Class<?> clz, List<Field> result) {
        Class<?> superclass = clz.getSuperclass();
        result.addAll(Arrays.asList(clz.getDeclaredFields()));
        if (ObjectUtils.isEmpty(superclass)) {
            return result;
        } else {
            return getSuperField(superclass, result);
        }
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值