Spring BeanUtils 的对象复制 copyProperties
Spring提供了一个非常棒的对象复制方法, 其参数的顺序和apache commons提供的同名方法是不一样的, 这个要小心.
源码
public static void copyProperties(Object source, Object target) throws BeansException { copyProperties(source, target, (Class)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, (Class)null, ignoreProperties); } private 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 ignoreList = ignoreProperties != null?Arrays.asList(ignoreProperties):null; PropertyDescriptor[] var7 = targetPds; int var8 = targetPds.length; for(int var9 = 0; var9 < var8; ++var9) { PropertyDescriptor targetPd = var7[var9]; Method writeMethod = targetPd.getWriteMethod(); if(writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) { PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName()); 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 ex = readMethod.invoke(source, new Object[0]); if(!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) { writeMethod.setAccessible(true); } writeMethod.invoke(target, new Object[]{ex}); } catch (Throwable var15) { throw new FatalBeanException("Could not copy property \'" + targetPd.getName() + "\' from source to target", var15); } } } } } }
可以看到, 成员变量赋值是基于目标对象的成员列表, 并且会跳过ignore的以及在源对象中不存在的, 所以这个方法是安全的, 不会因为两个对象之间的结构差异导致错误, 但是必须保证同名的两个成员变量类型相同.