在使用Struts2进行属性信息显示时,经常使用如下的显示语句:
<s:property value="xx.name"/>
而对于如上的语句,在后台则是使用ognl进行数据解析。在解析时,实际的执行代码类似于这样的处理逻辑
action.getXx().getName()
然而,在ognl里面是否是严格按照javaBean的解析方式呢,如果是这样的话,那就对了。但实际情况即不是,它自作聪明地想要自己去实际properDescripter,但却弄巧成拙(可以使用这个词)。
以下代码针对于 版本ognl 2.7.3以及3.0.5(最新的也存在这个问题)。
问题出现在获取getXx()这个方法上。对于像如下的属性声明:
public class Tx { private CGame cGame; public CGame getCGame(long[] ids) { return null; } public CGame getcGame() { return cGame; } }
在执行以下代码:
Tx t = new Tx(); System.out.println(Ognl.getValue("cGame", t));
它并不会返回正常的cGame,而是会报一个NoSuchMethodException的错误。在上面的javaBean中,由于CGame的声明方法为首2全字母为大写,根据javaBean的特殊规定,因此 getMethod直接为首字母小写形式,而并不是简单粗暴的getCGame()形式。但ognl即直接栽到这里了。在上面的Ognl.getValue("cGame")中,ognl会去找相应的getMethod,即会调用OgnlRuntime.getMethodValue(xxx)方法,方法内部代码如下所示:
Object result = null; Method m = getGetMethod(context, (target == null) ? null : target.getClass() , propertyName); //最终会调用到 getDeclaredMethods(targetClass, propertyName, false /* find 'get' methods */); //其中关键代码为 //以下代码在OgnlRuntime 1745行 3.0.5版本 //悲剧,强行将首字母大写了 String baseName = Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1); for (Class c = targetClass; c != null; c = c.getSuperclass()) { Method[] methods = c.getDeclaredMethods(); for (int i = 0; i < methods.length; i++) { if (!isMethodCallable(methods[i])) continue; String ms = methods[i].getName(); if (ms.endsWith(baseName)) {
因此,在以上的执行代码中,Ognl最终会找到getCCGame(long[])这个方法,并认为这个方法就是最终的方法,但由于它需要getMethod,因此它还会作一个判断,即判断参数列表为0。结果惟一的getCCgame(long[])就被排除了。最后就会报一个NoSuchMethodException错误。而我们正确的getcGame()方法,从一开始就被排除在Ognl的查找范围之外。
要解决以上的问题,方法也很简单,一是将属性名修改为首2位字母均为小写的情况,另一个方法就是再写一个叫getCGame()的方法,里面直接返回getcGame()。但这两种方法,均不是最妥的方法,但也只能这样做了。
转载请标明出处:i flym
本文地址:https://www.iflym.com/index.php/code/201207120001.html