BeanUtils.copyProperties方法的复制忽略指定属性实现

【辰兮要努力】:hello你好我是辰兮,很高兴你能来阅读,昵称是希望自己能不断精进,向着优秀程序员前行!

博客来源于项目以及编程中遇到的问题总结,偶尔会有读书分享,我会陆续更新Java前端、后台、数据库、项目案例等相关知识点总结,感谢你的阅读和关注,希望我的博客能帮助到更多的人,分享获取新知,大家一起进步!

吾等采石之人,应怀大教堂之心,愿我们奔赴在各自的热爱里…

一、案例学习

在这里插入图片描述

在实际开发中,有时候我们需要将一个Java Bean的属性值复制到另一个Java Bean中。但是有一些情况下,我们不想复制所有属性,而是需要忽略某些属性。例如,两个Java Bean的属性名称不一致,我们需要忽略属性名称不一致的属性。这时候,就可以使用BeanUtils.copyProperties方法的复制忽略指定属性实现。

import lombok.Data;
import org.springframework.beans.BeanUtils;

import java.util.ArrayList;

@Data
public class Student {
    private String name;
    private int age;
    private String gender;

    // getters and setters...

    public static void main(String[] args) throws Exception {
        ArrayList<Student> students = new ArrayList<>();
        for (int i = 0; i < 3; i++) {
            Student student = new Student();
            student.setName("Student " + i);
            student.setAge(i * 10);
            student.setGender("Male");
            students.add(student);
        }

        // 使用 BeanUtils.copyProperties 复制学生信息,但忽略性别属性
        ArrayList<Student> copiedStudents = new ArrayList<>();
        for (Student student : students) {
            Student copiedStudent = new Student();
            String[] ignoredProperties = {"gender"}; // 指定忽略的属性
            BeanUtils.copyProperties(student, copiedStudent, ignoredProperties);
            copiedStudents.add(copiedStudent);
        }

        System.out.println("Original Students:");
        for (Student student : students) {
            System.out.println(student.getName() + ", Age: " + student.getAge()
                    + ", Gender: " + student.getGender() );
        }

        System.out.println("Copied Students:");
        for (Student student : copiedStudents) {
            System.out.println(student.getName() + ", Age: " + student.getAge()
                    + ", Gender:  " + student.getGender() );
        }
    }
}

执行结果

Original Students:
Student 0, Age: 0, Gender: Male
Student 1, Age: 10, Gender: Male
Student 2, Age: 20, Gender: Male
Copied Students:
Student 0, Age: 0, Gender:  null
Student 1, Age: 10, Gender:  null
Student 2, Age: 20, Gender:  null

对比

在这里插入图片描述


二、源码学习

BeanUtils.copyProperties()是Spring Framework中的一个工具类,用于将一个JavaBean中的属性值复制到另一个JavaBean中。它的源码如下:

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

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

public static void copyProperties(Object source, Object target, Class<?> editable, 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 = getPropertyDescriptors(actualEditable);
    List<String> ignoreList = (ignoreProperties != null) ? Arrays.asList(ignoreProperties) : null;
    for (PropertyDescriptor targetPd : targetPds) {
        if (targetPd.getWriteMethod() == null || (ignoreList != null && ignoreList.contains(targetPd.getName()))) {
            continue;
        }
        PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
        if (sourcePd != null && sourcePd.getReadMethod() != null) {
            try {
                Method readMethod = sourcePd.getReadMethod();
                if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
                    readMethod.setAccessible(true);
                }
                Object value = readMethod.invoke(source);
                Method writeMethod = targetPd.getWriteMethod();
                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);
            }
        }
    }
}

该方法的实现逻辑如下:

  1. 首先进行参数校验,source和target参数不能为空;
  2. 如果editable参数不为空,则如果target不是该editable的实例,则抛出异常;
  3. 如果editable参数为空,那么就将target.getClass()的值赋给actualEditable;
  4. 获取目标对象(target)的PropertyDescriptor数组;
  5. 如果ignoreProperties不为空,则将其转换为List对象,否则赋值为null;
  6. 对于每个PropertyDescriptor对象,判断其是否有WriteMethod方法,以及是否在ignoreProperties中,如果符合条件,则跳过;
  7. 获取源对象(source)中与目标对象中相同属性名的PropertyDescriptor对象;
  8. 如果sourcePd不为空,且sourcePd有ReadMethod方法,则执行以下操作:
    1. 获取sourcePd中的方法对象(Method);
    2. 如果该方法的修饰符不是public,则将其设置为可访问的;
    3. 调用该方法获取到其返回值(value);
    4. 获取targetPd中的方法对象(Method);
    5. 如果该方法的修饰符不是public,则将其设置为可访问的;
    6. 调用该方法,将value设置为其参数值;
  9. 如果发生异常,则抛出FatalBeanException异常。

总体来说,该方法的实现逻辑比较清晰,先进行参数校验,然后对目标对象的PropertyDescriptor数组进行遍历,在每次遍历时,将源对象中与目标对象中属性名相同的PropertyDescriptor对象的ReadMethod方法获取到,然后调用它获取到其返回值,最后再调用目标对象的PropertyDescriptor对象的WriteMethod方法,将值设置为其参数值。

在这里插入图片描述


📖☕️🌊📝📚🎩🚀
📣非常感谢你阅读到这里,如果这篇文章对你有帮助,希望能留下你的点赞👍 关注❤️ 分享👥 留言💬thanks!!!

📚愿我们奔赴在各自的热爱里!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员可乐丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值