当前位置: 代码迷 >> 综合 >> 使用springframework中BeanUtils.copyProperties的坑
  详细解决方案

使用springframework中BeanUtils.copyProperties的坑

热度:52   发布时间:2024-02-10 17:05:02.0

一、属性无法复制

  1. target 必须是 editable 的子类。
  2. source 属性的 get 方法必须是 public 才能复制。
  3. target 属性没有 set 方法的无法复制。
  4. target 的 set 方法不是 public 无法复制。
  5. 对于某一个相同属性名的属性: 如果 source 和 target 不同类型,无法复制; source 和 target 类型相同,可以复制; source extends target 可以复制。

二、复制流程分析

1、判断 target 是否是 editable 的子类。如果不是就报错,是继续下面的逻辑。

2、取出 target 的所有属性。

3、对 target 的每一个属性进行遍历。

3.1、拿到 target 属性的 set 方法。排除不需要复制的属性。拿不到,返回。

3.2、取出 source 属性的 set 和 get 方法。

3.3、判断 target 的 set 的类是否能转化为 source 的 get 类。无法转换,返回。

3.4、判断 source 的 get 方法是否是 public。

3.5、使用反射调用 source 的 get 方法,获取到值。

3.6、判断 target 的 set 方法是否是 public 修饰。

3.7、使用反射调用 target 的 set 方法,设置值。

4、复制属性成功,进行下一个属性的复制。

三、核心代码分析 

    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) {// 判断 target 是否是 editable 的子类。if (!editable.isInstance(target)) {throw new IllegalArgumentException("Target class [" + target.getClass().getName() +"] not assignable to Editable class [" + editable.getName() + "]");}actualEditable = editable;}// 读取 editable/target(editable>target) 的所有的属性。PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);// 排除某些不需要复制的属性。List<String> ignoreList = (ignoreProperties != null ? Arrays.asList(ignoreProperties) : null);// 对 target 的每一个属性进行遍历。for (PropertyDescriptor targetPd : targetPds) {// 拿到 target 属性的写方法(set方法)。Method writeMethod = targetPd.getWriteMethod();if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {// 拿到相应的属性修饰器。PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());if (sourcePd != null) {// 拿到 source 的 get 方法。Method readMethod = sourcePd.getReadMethod();// 首先 source 属性是有 get 方法,target 的 set 的类是否能转化为 source 的 get 类。if (readMethod != null &&ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {try {// 判断 source 的 get 方法是否是 public。if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {readMethod.setAccessible(true);}// 使用反射调用 source 的 get 方法,获取到值。Object value = readMethod.invoke(source);// 判断 target 的 set 方法是否是 public 修饰。if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {writeMethod.setAccessible(true);}// 使用反射调用 target 的 set 方法,设置值。writeMethod.invoke(target, value);}catch (Throwable ex) {throw new FatalBeanException("Could not copy property '" + targetPd.getName() + "' from source to target", ex);}}}}}}

 

 

 

 

 

 

 

 

  相关解决方案