一芍耘、 問題
項目中使用EasyPoi工具開發(fā)excel導(dǎo)出功能开镣,導(dǎo)出類中有如下結(jié)構(gòu)字段:
"X_XXX_XXX"哗咆,字段首位只有一個字符究抓。
使用導(dǎo)出api猾担,發(fā)生異常:
There is no getter for property named 'XXX' in 'null'
檢查實體類,存在對應(yīng)的getXXX刺下,setXXX方法绑嘹。
這就很詭異了,為什么橘茉?
二工腋、 分析
找到源碼異常點在工具類PoiReflectorUtil中:
可以看到在method沒有找到對應(yīng)名稱的字段:getMethods是一個Map用來保存字段信息,找到對應(yīng)put方法:
我們從此工具類PoiReflectorUtil的初始化開始看:
在構(gòu)造函數(shù)中分別通過反射獲取了實例的get方法,set方法和屬性:
addGetMethod(clazz)方法:
可以看到此方法做了三件事:
- 通過反射獲取實體的所有方法
- 分別處理以“get”畅卓,"is"開頭的方法
- 處理后的結(jié)果保存在map中
再看如何處理: 截取"get"擅腰,"set"或者"is" ,判斷后面的字符:如果長度==1或者第一個字符不是大寫則將首字符轉(zhuǎn)換為小寫翁潘。
好像發(fā)現(xiàn)了什么趁冈,結(jié)構(gòu)為"X_XXX_XXX"的字段:"P_TEST_VLUE",根據(jù)JAVA的變量規(guī)則為:pTestValue拜马,對應(yīng)的get方法名“getPTestValue( )”渗勘,而根據(jù)上面的規(guī)則,因為"PTestValue"第二個字符為大寫一膨,所以并不會將首位轉(zhuǎn)為小寫Q叫稀!豹绪!也許這就解釋了為什么在后面的邏輯中找不到“pTestValue”字段。
在上一步的resolveGetterConflicts方法中通過addGetMethod加入getMethods保存申眼。
addFileds(clazz)方法:
同樣使用反射獲取了所有的字段信息瞒津,并加入到了fieldList中。加入的字段為:“pTestValue”括尸。
ps: 請注意這個方法:設(shè)置私有字段的訪問權(quán)限
field.setAccessible(true)
最后再看拋出異常的地方:
由上面的分析可以發(fā)現(xiàn)問題所在巷蚪,正由猜測的一樣,因為在“getMethods”中保存的字段名為:“PTestValue”濒翻,而只有字段名為“pTestValue”屁柏,get方法取值為null:
Method method = getMethods.get(propertyName);
最終在執(zhí)行導(dǎo)出方法的時候,執(zhí)行到了前面拋出異常的方法:
四有送、總結(jié)
因為以前沒有遇到過形如"X_XXX_XXX"的字段淌喻,對此通過反射獲取實體類的方法不是很了解。只有查看源碼才能發(fā)現(xiàn)端倪雀摘。
這里賣個關(guān)子裸删,jackson序列化工具也有類似的問題。