BeanUtils.copyProperties忽略某些字段的值及其原理

1. 用法

例如: BeanUtils.copyProperties(beforeObj, route, new String[] { "id", "createDate", "modifyDate" });java

包名为:org.springframework.beansspring

2. 源代码分析

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对象
		 * java.lang.Class类里边有不少实用的方法 当你获得一个对象的Class对象以后就能够调用这些方法
		 * 例如:
		 * Method m = gTResultVo.getClass().getDeclaredMethod("set" + classMethod, String.class);
		 * m.invoke(gTResultVo, value);
		 * 经过Class类的getDeclaredMethod获取gTResultVo类的某个set方法,而后进行赋值
		 */
		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类表示JavaBean类经过存储器导出一个属性。
		 * 主要方法:
		 * 一、getPropertyType(),得到属性的Class对象。
		 * 二、getReadMethod(),得到用于读取属性值的方法;getWriteMethod(),得到用于写入属性值的方法。
		 * 三、hashCode(),获取对象的哈希值。
		 * 四、setReadMethod(Method readMethod),设置用于读取属性值的方法;setWriteMethod(MethodwriteMethod),设置用于写入属性值的方法;
		 */
		PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);

		/**
		 * Arrays.asList(ignoreProperties):把String[]转换成列表
		 */
		List<String> ignoreList = (ignoreProperties != null ? Arrays.asList(ignoreProperties) : null);

		for (PropertyDescriptor targetPd : targetPds) {
			Method writeMethod = targetPd.getWriteMethod();//得到用于写入属性值的方法
			/**
			 * 判断是否有忽略属性或当前属性是否在忽略属性中
			 * !ignoreList.contains(targetPd.getName()):利用列表的contains直接判断是否含有该属性
			 */
			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 value = readMethod.invoke(source);//获取source的该属性值
							if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
								writeMethod.setAccessible(true);
							}
							writeMethod.invoke(target, value);//利用获取到的writeMethod给target赋值
						}
						catch (Throwable ex) {
							throw new FatalBeanException(
									"Could not copy property '" + targetPd.getName() + "' from source to target", ex);
						}
					}
				}
			}
		}
	}
public static boolean isAssignable(Class<?> lhsType, Class<?> rhsType) {
		Assert.notNull(lhsType, "Left-hand side type must not be null");
		Assert.notNull(rhsType, "Right-hand side type must not be null");
		
		/**
		 * instanceof:
		 * 用法:boolean 对象 instanceof 类型
		 * 解释:用于判断某一个对象是不是该类型的实例
		 * 
		 * Class.isAssignableFrom(Class<?> clazz)
		 * 用法:boolean  class.isAssignableFrom(Class<?> clazz)
		 * 解释:calss是否与参数clazz相同,或class是clazz的父类或接口。
		 */
		if (lhsType.isAssignableFrom(rhsType)) {
			return true;
		}
		/**
		 * isPrimitive:肯定指定的Class对象表示一个基本类型,当且仅当这个类表示一个基本类型此方法返回true。
		 * primitiveWrapperTypeMap:包装类做为key,原始类型做为value的基本类型集合;例如:primitiveWrapperTypeMap.put(Boolean.class, boolean.class);
		 */
		if (lhsType.isPrimitive()) {
			Class<?> resolvedPrimitive = primitiveWrapperTypeMap.get(rhsType);
			if (lhsType == resolvedPrimitive) {
				return true;
			}
		}
		/**
		 * primitiveTypeToWrapperMap:原始类型做为key,包装类做为value的基本类型集合;
		 */
		else {
			Class<?> resolvedWrapper = primitiveTypeToWrapperMap.get(rhsType);
			if (resolvedWrapper != null && lhsType.isAssignableFrom(resolvedWrapper)) {
				return true;
			}
		}
		return false;
	}
相关文章
相关标签/搜索