Spring 中的BeanUtils与apache中的BeanUtils差别 及 jodd改造

Spring 中的BeanUtils与apache中的BeanUtils区别

org.apache.commons.beanutils.BeanUtils#copyProperties方法会进行类型转换,默认情况下会将Ineger、Boolean、Long等基本类型包装类为null时的值复制后转换成0或者false,有时这个可能会引起不必要的麻烦。

而org.springframework.beans.BeanUtils.copyProperties();则不会!

还有很多 ,比如 Apache的不能忽略特定属性

具体大家可以参考官网

这里主要改造下

https://jodd.org/beanutil/   用到了这个包

BeanUtils.copy(vo,entity);

public class BeanUtils {

	/**
	 * 复制所有与目标对象的属性相匹配的源对象中的属性值到目标对象中。(源对象中的null值也同样会被复制)
	 *
	 * @param srcBean
	 * @param dstBean
	 */
	public static void copy(Object srcBean, Object dstBean) {
		copy(srcBean, dstBean, null, (Collection<String>) null);
	}

    /**
	 * 考虑被忽略属性列表与属性名称转换表,将复制所有与目标对象的属性相匹配的源对象中的属性值到目标对象中。 (源对象中的null值也同样会被复制).
	 *
	 * @param srcBean
	 * @param dstBean
	 * @param revertMap
	 *            由目标属性名称到源属性名称的映射表
	 * @param ignoredProps
	 *            被忽略的属性集合
	 */
	public static void copy(Object srcBean, Object dstBean, Map<String, String> revertMap, Collection<String> ignoredProps) {
		copy(srcBean, dstBean, revertMap, ignoredProps, null, true);
	}

    /**
	 * 提交基本的Bean操作能力。
	 * 
	 * 所有的Bean操作的规范如下: 按目标Bean中的所有属性(如果指定了待复制属性列表,则仅限于待复制属性列表),
	 * 如果该属性不在被忽略属性中,且有源Bean中的对应属性, 则以源Bean中的对应属性设置目标Bean中的属性。 源与目标间的属性对应方式为:
	 *      如果存在映射表, 以则目标对象中的属性为key从映射表中查到的字符串为源对象中的属性名称。 
     *      如果不存在映射表,或映射表中不包含指定的属性,则源对象中的属性名称与目标对象的属性名称相同。
	 *
	 * @param srcBean
	 * @param dstBean
	 * @param revertMap
	 *            属性转换表, 为空则不转换。 属性转换表中不存在的项目也不做转换。
	 * @param ignoredProps
	 *            被忽略的属性列表
	 * @param props
	 *            希望被复制的属性
	 * @param copyNull
	 *            是否复制空值。
	 */
	private static void copy(Object srcBean, Object dstBean, Map<String, String> revertMap, Collection<String> ignoredProps,
			Collection<String> props, boolean copyNull) {
		copy(srcBean, dstBean, revertMap, ignoredProps, props, copyNull, true);
	}

    private static void copy(Object srcBean, Object dstBean, Map<String, String> revertMap, Collection<String> ignoredProps,
			Collection<String> props, boolean copyNull, boolean copyEmptyStr) {
		String[] properties = BeanTool.resolveProperties(dstBean, true);
		String srcPropName;
		Object value;
        //遍历 目标bean 中的属性 
        //map映射表中的key为dstBean的属性,value为srcBean中的属性,把srcBean中的名叫value的属性 复制到 dstBean中名为key的属性
        //如果映射表中不存在对应的映射,则是属性名对应映射
		for (String property : properties) {
			// 过滤掉不在指定属性列表中的属性
			if (props != null && !props.contains(property)) {
				continue;
			}
			// 过滤掉在忽略属性列表中的属性
			if (ignoredProps != null && ignoredProps.contains(property)) {
				continue;
			}

			if (revertMap != null) {
				srcPropName = revertMap.get(property);
				if (srcPropName == null) {
					srcPropName = property;
				}
			} else {
				srcPropName = property;
			}

			// 使用Silently版本, 这样将允许不存在的目标字段存在而继续工作,但这样也将掩盖一些问题。
			value = BeanUtil.getPropertySilently(srcBean, srcPropName);
			if (value == null && !copyNull) {
				continue;
			}
			// 只处理"" 不处理 " "
			if (value != null && value.toString().length() == 0 && !copyEmptyStr) {
				continue;
			}
			BeanUtil.setPropertySilent(dstBean, property, value);
		}
	}

里面用到了 BeanTool.resolveProperties  就是 jodd 提供的

/**
	 * Returns an array of bean properties. If bean is a map, all its
	 * keys will be returned.
	 */
	public static String[] resolveProperties(Object bean, boolean suppressSecurity) {
		String[] properties;
		if (bean instanceof Map) {
			Set key = ((Map) bean).keySet();
			String[] mdata = new String[key.size()];
			int ndx = 0;
			for (Object o : key) {
				mdata[ndx] = o.toString();
				ndx++;
			}
			properties = mdata;
		} else {
			ClassDescriptor cdSrc = ClassIntrospector.lookup(bean.getClass());
			properties = cdSrc.getAllBeanGetterNames(suppressSecurity);
		}

		return properties;
	}

主要看注释

 

 

附上spring BeanUtils copyProperties源码,对于新增操作中vo转entity 可以直接用这个,但当修改是不应该用这个,他会把null值也赋值过去

 

org.springframework.beans
类BeanUtils
java.lang.Object继承
org.springframework.beans.BeanUtils

static void    copyProperties(java.lang.Object source, java.lang.Object target)
将给定源bean的属性值复制到目标bean中。
注意:只要属性匹配,源类和目标类就不必相互匹配,甚至不必相互派生。源bean暴露但目标bean不会被忽略的任何bean属性。
这只是一种方便的方法。对于更复杂的传输需求,请考虑使用完整的BeanWrapper。
参数:
source - 源bean
target - 目标bean
抛出:
BeansException - 如果复制失败
也可以看看:
BeanWrapper

static void    copyProperties(java.lang.Object source, java.lang.Object target, java.lang.Class<?> editable)
将给定源bean的属性值复制到给定目标bean中,仅设置在给定“可编辑”类(或接口)中定义的属性。

static void    copyProperties(java.lang.Object source, java.lang.Object target, java.lang.String... ignoreProperties)
将给定源bean的属性值复制到给定的目标bean中,忽略给定的“ignoreProperties”。
//ignoreProperties是要忽略的属性数组

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

        //该方法返回JavaBean的属性描述器数组。
        PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
        //如果ignoreProperties不为null,将要忽略的属性数组转换为List<String> ignoreList
        List<String> 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 value = readMethod.invoke(source);
                            if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
                                writeMethod.setAccessible(true);
                            }

                            writeMethod.invoke(target, value);
                        } catch (Throwable var15) {
                            throw new FatalBeanException("Could not copy property '" + targetPd.getName() + "' from source to target", var15);
                        }
                    }
                }
            }
        }

    }
}
可以看出spring的BeanUtils可以忽略指定属性,但是null值也会被copy

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值