【Spring】BeanUtils.copyPorperties()的IllegalArgumentException原因分析

  • 前置知识: SpringBean ORM Java企业级开发基础

背景

在使用ORM框架读取数据库表记录时,为了把PO(Persist Object)转换成BO(Business Object),由于PO和BO中的字段绝大多数情况下高度重合,因此copyProperties()也是经常使用的函数,但是如果使用不当就会抛出Exception

举个例子,有这么一个系统:

  1. Database的Table中有data字段(tinyint)
  2. PO中有data字段(Boolean)
  3. BO中有data字段(boolean)

在数据库的data字段为null时,调用copyProperties(PO,BO)时就会抛出异常:Caused by java.lang.IllegalArgumentException

代码分析

Example of copyProperties()

private static void copyProperties(Object source, Object target, Class<?> editable, String[] ignoreProperties)
            throws BeansException {
/** 略 **/
                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 properties from source to target", ex);
                    }
                }
    /** 略 **/
}

总结一下: 该方法复制字段(可以不同Class,但是目标字段的类型必须和源字段类型兼容)原理是获得源对象字段的getter方法和目标对象字段的setter方法

Example of PO and its ReadMethod

private Boolean data;
public Boolean getData(Boolean data){
   return this.data;
}

Example of BO and its WriteMethod

private boolean data;
public setData(boolean data){
    this.data = data;
}

具体就是挂在调用BO.setData(null)时, 对一个基本类型boolean赋值为null

措施分析

  1. 新增数据库字段时指定默认值,并设置为Not Null
  2. 为PO的字段指定默认值,如private Boolean data = true;

    • _推荐这种方式_,因为BO中字段为基本类型,上面的业务层就不需要额外判断是否是null
    • 如果表中数据为null,则ORM(iBatis/MyBatis)不会调用PO相应字段的setter方法,所以为PO的字段指定默认值是可行的
    原文作者:Jiadong
    原文地址: https://segmentfault.com/a/1190000010048652
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞