- 前置知识: SpringBean ORM Java企业级开发基础
背景
在使用ORM
框架读取数据库表记录时,为了把PO(Persist Object)转换成BO(Business Object),由于PO和BO中的字段绝大多数情况下高度重合,因此copyProperties()
也是经常使用的函数,但是如果使用不当就会抛出Exception
举个例子,有这么一个系统:
- Database的Table中有data字段(tinyint)
- PO中有data字段(Boolean)
- 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
措施分析
- 新增数据库字段时指定默认值,并设置为
Not Null
为PO的字段指定默认值,如
private Boolean data = true;
- _推荐这种方式_,因为BO中字段为基本类型,上面的业务层就不需要额外判断是否是
null
了 - 如果表中数据为
null
,则ORM(iBatis/MyBatis)不会调用PO相应字段的setter
方法,所以为PO的字段指定默认值是可行的
- _推荐这种方式_,因为BO中字段为基本类型,上面的业务层就不需要额外判断是否是