实现不同属性名称的对象拷贝

实现不同属性名称的属性拷贝

import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeansException;
import org.springframework.beans.FatalBeanException;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 功能描述: bean工具类:
 *          目前实现的功能有: bean的拷贝功能:拓展SpringBeanUtils的属性拷贝功能,可提供map实现源对象与目标对象不同属性的匹配
 * @author luxiaomeng
 * @date  2021/8/16 13:53
 * @修改日志:
 */
public class BeanUtils {


    /**【拓展】拓展springBeanUtils,可以给定一个map key存储源对象的字段值,value存储目标对象的字段,可以实现两个不同字段名称间的属性复制
     *
     * Copy the property values of the given source bean into the given target bean.
     * 将给定源 bean 的属性值复制到给定目标 bean 中。
     * <p>Note: The source and target classes do not have to match or even be derived  from each other, as long as the properties match.
     * <p>注意: 只要属性匹配,源类和目标类不必匹配,甚至不必相互派生。
     * Any bean properties that the source bean exposes but the target bean does not will silently be ignored.
     * 源 bean 公开但目标 bean 没有公开的任何 bean 属性都将被静默忽略。
     *
     * @param source the source bean 源对象(bean)
     * @param target the target bean 目标对象(bean)
     * @param editable the class (or interface) to restrict property setting to 将属性设置限制为的类(或接口)
     * @param map 字段映射map   key存储源对象的字段值,value存储目标对象的字段
     * @param ignoreProperties array of property names to ignore 要忽略的属性名称数组
     * @throws BeansException if the copying failed 如果复制失败
     * @see BeanWrapper
     */
    private static void copyProperties(Object source, Object target, @Nullable Class<?> editable,
                                       @Nullable Map<String, String> map, @Nullable String... ignoreProperties) throws BeansException {

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

        // 拿到目标对象字节码对象
        Class<?> actualEditable = source.getClass();
        if (editable != null) {
            if (!editable.isInstance(source)) {
                throw new IllegalArgumentException("Source class [" + source.getClass().getName() +
                        "] not assignable to Editable class [" + editable.getName() + "]");
            }
            actualEditable = editable;
        }
        // PropertyDescriptor描述Java Bean中通过一对存储器方法(getter / setter)导出的一个属性。我们可以通过该PropertyDescriptor对bean中的该属性进行读取和写入操作,也可以设置其getter / setter。
        PropertyDescriptor[] sourcePds = BeanUtils.getPropertyDescriptors(actualEditable);
        List<String> ignoreList = (ignoreProperties != null ? Arrays.asList(ignoreProperties) : null);

        // 遍历目标对象的属性
        for (PropertyDescriptor sourcePd : sourcePds) {
            Method readMethod = sourcePd.getReadMethod();
            if (readMethod != null && (ignoreList == null || !ignoreList.contains(sourcePd.getName()))) {
                PropertyDescriptor targetPd = null;
                // 如果map有,则取map中的字段
                if (map != null && map.get(sourcePd.getName()) != null && !"".equals(map.get(sourcePd.getName()))) {
                    targetPd = BeanUtils.getPropertyDescriptor(target.getClass(), map.get(sourcePd.getName()));
                } else {
                    // 如果map没有,则找相同名称的字段
                    targetPd = BeanUtils.getPropertyDescriptor(target.getClass(), sourcePd.getName());
                }
                if (targetPd != null) {
                    Method writeMethod = targetPd.getWriteMethod();
                    if (writeMethod != 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 '" + targetPd.getName() + "' from source to target", ex);
                        }
                    }
                }
            }
        }
    }

    /**
     * 功能描述: 属性复制
     * @param source 源对象
     * @param target 目标对象
     * @param ignoreProperties 忽略的属性
     * @author luxiaomeng
     * @date  2021/8/16 13:57
     * @修改日志:
     */
    public static void copyProperties(Object source, Object target, String... ignoreProperties) throws BeansException {
        copyProperties(source, target, null,null, ignoreProperties);
    }

    /**
     * 功能描述: 属性复制
     * @author luxiaomeng
     * @date  2021/8/16 14:00
     * @修改日志:
     */
    public static void copyProperties(Object source, Object target) throws BeansException {
        copyProperties(source, target, null,null, (String[]) null);
    }

    /**
     * 功能描述: 属性复制
     * @param source 源对象
     * @param target 目标对象
     * @param map 字段映射map
     * @author luxiaomeng
     * @date  2021/8/16 14:33
     * @修改日志:
     */
    public static void copyProperties(Object source, Object target,Map<String,String> map) throws BeansException {
        copyProperties(source, target, null,map, (String[]) null);
    }

    /**
     * 功能描述: 测试
     *
     * @author luxiaomeng
     * @date 2021/8/16 14:35
     * @修改日志:
     */
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();
        map.put("a", "b");
        A a = new A();
        B b = new B();
        a.setA("a");
        // 将a类中的 属性a 的值, 复制到B中的属性b
        BeanUtils.copyProperties(a, b, map);
        System.out.println(b.toString());

    }

}
class B {
    private String b;

    public String getB() {
        return b;
    }

    public void setB(String b) {
        this.b = b;
    }

    @Override
    public String toString() {
        return "B{" +
                "b='" + b + '\'' +
                '}';
    }
}
class A {
    private String a;
    private String c;

    public String getC() {
        return c;
    }

    public void setC(String c) {
        this.c = c;
    }

    public String getA() {
        return a;
    }

    public void setA(String a) {
        this.a = a;
    }
}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值