Bootstrap

属性名称不一致,实现 bean copyProperties

在这里插入图片描述在这里插入图片描述

这种情况, 要copy bean 是不是很难受 ,假如有N个字段名不一样,每个都要set,瞬间想砸键盘吗?
用个工具类,从此省下键盘钱,去撩妹不香吗?

上代码

1、来个注解

@Inherited
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface CopySourceName {
    
    String value();

}

2、工具类


public class CopyBeanUtils {

    /**
     * ps:Test2 test2 = CopyBeanUtils.springCopyProperties(i1, Test2.class);
     *
     * @param source      原对象
     * @param targetClass 目标对象class
     * @param <T>
     * @return copy完后的对象
     */
    public static <T> T springCopyProperties(Object source, Class<T> targetClass) {
        Assert.notNull(source, "targetClass must not be null");

        T target = BeanUtils.instantiateClass(targetClass);
        BeanUtils.copyProperties(source, target);
        return target;
    }

    /**
     * ps:Test2 test2 = CopyBeanUtils.copyProperties(i1, Test2.class);
     *
     * @param source      原对象
     * @param targetClass 目标对象class
     * @param <T>
     * @return copy完后的对象
     */
    public static <T> T copyProperties(Object source, Class<T> targetClass) {
        Assert.notNull(source, "targetClass must not be null");

        T target = BeanUtils.instantiateClass(targetClass);
        copyProperties(source, target);
        return target;
    }

    public static void copyProperties(Object source, Object target) throws BeansException {
        copyProperties(source, target, null, (String[]) null);
    }

    public static void copyProperties(Object source, Object target, Class<?> editable) throws BeansException {
        copyProperties(source, target, editable, (String[]) null);
    }

    /**
     * @param source           原对象
     * @param target           目标对象
     * @param ignoreProperties 排除某些不需要复制的属性
     * @throws BeansException
     */
    public static void copyProperties(Object source, Object target, String... ignoreProperties) throws BeansException {
        copyProperties(source, target, null, ignoreProperties);
    }

    private static void copyProperties(Object source, Object target, @Nullable Class<?> editable, @Nullable String... ignoreProperties) throws BeansException {

        Assert.notNull(source, "Source must not be null");
        Assert.notNull(target, "Target must not be null");

        Class<?> actualEditable = target.getClass();
        if (editable != null) {
            if (!editable.isInstance(target)) {
                throw new IllegalArgumentException("Target class [" + target.getClass().getName() +
                        "] not assignable to Editable class [" + editable.getName() + "]");
            }
            actualEditable = editable;
        }
        PropertyDescriptor[] targetPds = BeanUtils.getPropertyDescriptors(actualEditable);
        List<String> ignoreList = (ignoreProperties != null ? Arrays.asList(ignoreProperties) : null);

        HashMap<String, String> copySourceNameMap = new HashMap<>();

        for (Field field : actualEditable.getDeclaredFields()) {
            CopySourceName annotation = field.getAnnotation(CopySourceName.class);
            if (annotation != null) {
                copySourceNameMap.put(field.getName(), annotation.value());
            }
        }

        for (PropertyDescriptor targetPd : targetPds) {
            Method writeMethod = targetPd.getWriteMethod();
            String name = targetPd.getName();
            String sourceName = copySourceNameMap.get(name);
            if (sourceName != null) name = sourceName;
            if (writeMethod != null && (ignoreList == null || !ignoreList.contains(name))) {
                PropertyDescriptor sourcePd = BeanUtils.getPropertyDescriptor(source.getClass(), name);
                if (sourcePd != null) {
                    Method readMethod = sourcePd.getReadMethod();
                    if (readMethod != null &&
                            ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {
                        try {
                            if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
                                readMethod.setAccessible(true);
                            }
                            Object value = readMethod.invoke(source);
                            if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
                                writeMethod.setAccessible(true);
                            }
                            writeMethod.invoke(target, value);
                        } catch (Throwable ex) {
                            throw new FatalBeanException(
                                    "Could not copy property '" + name + "' from source to target", ex);
                        }
                    }
                }
            }
        }
    }

}

3、测试类

@Data
@Accessors(chain = true)
public class Test1 {

    private String str;

    private List<String> userIds;
}


@Data
@Accessors(chain = true)
public class Test2 {

    private String str;

    @CopySourceName("userIds")
    private List<String> userIdList;
}


public class test {

    public static void main(String[] args) {
        Test1 i1 = new Test1().setStr( "11").setUserIds(CollectionUtil.toList("i", "2222", "111"));
        Test2 test2 = CopyBeanUtils.copyProperties(i1, Test2.class);
        System.out.println(JSONUtil.toJsonStr(test2 ));
    }
}

实现逻辑基本一致,增加了一点代码

工具类 对比 Spring 的 BeanUtils.copyProperties(source, target); 运行速度 单位ms

第一次50次5000次50000次1000000次5000000次
spring11511686748429
工具类67126010965312
第二次50次5000次50000次1000000次5000000次
spring10652006387692
工具类34923711844359
第三次50次5000次50000次1000000次5000000次
spring14862116858100
工具类48025910725266
第四次50次5000次50000次1000000次5000000次
spring27711577158242
工具类410728110823354
第五次50次5000次50000次1000000次5000000次
spring91211686539455
工具类38523210595726
;