一、 问题
项目中使用EasyPoi工具开发excel导出功能,导出类中有如下结构字段:
"X_XXX_XXX",字段首位只有一个字符。
使用导出api,发生异常:
There is no getter for property named 'XXX' in 'null'
检查实体类,存在对应的getXXX,setXXX方法。
这就很诡异了,为什么?
二、 分析
找到源码异常点在工具类PoiReflectorUtil中:
可以看到在method没有找到对应名称的字段:getMethods是一个Map用来保存字段信息,找到对应put方法:
image.png我们从此工具类PoiReflectorUtil的初始化开始看:
在构造函数中分别通过反射获取了实例的get方法,set方法和属性:
addGetMethod(clazz)方法:
image.png可以看到此方法做了三件事:
- 通过反射获取实体的所有方法
- 分别处理以“get”,"is"开头的方法
- 处理后的结果保存在map中
再看如何处理: 截取"get","set"或者"is" ,判断后面的字符:如果长度==1或者第一个字符不是大写则将首字符转换为小写。
image.png好像发现了什么,结构为"X_XXX_XXX"的字段:"P_TEST_VLUE",根据JAVA的变量规则为:pTestValue,对应的get方法名“getPTestValue( )”,而根据上面的规则,因为"PTestValue"第二个字符为大写,所以并不会将首位转为小写!!!也许这就解释了为什么在后面的逻辑中找不到“pTestValue”字段。
在上一步的resolveGetterConflicts方法中通过addGetMethod加入getMethods保存。 image.png
addFileds(clazz)方法:
同样使用反射获取了所有的字段信息,并加入到了fieldList中。加入的字段为:“pTestValue”。
ps: 请注意这个方法:设置私有字段的访问权限
field.setAccessible(true)
最后再看抛出异常的地方:
由上面的分析可以发现问题所在,正由猜测的一样,因为在“getMethods”中保存的字段名为:“PTestValue”,而只有字段名为“pTestValue”,get方法取值为null:
Method method = getMethods.get(propertyName);
最终在执行导出方法的时候,执行到了前面抛出异常的方法:
image.png四、总结
因为以前没有遇到过形如"X_XXX_XXX"的字段,对此通过反射获取实体类的方法不是很了解。只有查看源码才能发现端倪。
这里卖个关子,jackson序列化工具也有类似的问题。
网友评论