- 前置知識: 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中欄位為基本型別,上面的業務層就不需要額外判斷是否是