《刨根问底--ognl--get获取数据》详细的解释了。ognl获取数据的过程。ognl设置数据的过程和获取数据的过程大部分都想同,只是后面的几部有所不一样,所以步骤1到10参照《刨根问底--ognl--get获取数据》文章。
首先看一下整个流程图:
10、OgnlRuntime类中setMethodValue()代码:
public static final boolean setMethodValue(OgnlContext context, Object target, String propertyName, Object value, boolean checkAccessAndExistence) throws OgnlException, IllegalAccessException, NoSuchMethodException, MethodFailedException, IntrospectionException
{
boolean result = true;
Method m = getSetMethod(context, (target == null) ? null : target.getClass(), propertyName);
if (checkAccessAndExistence) {
if ((m == null) || !context.getMemberAccess().isAccessible(context, target, m, propertyName)) {
result = false;
}
}
if (result) {
if (m != null) {
Object[] args = objectArrayPool.create(value);
try {
callAppropriateMethod(context, target, target, m.getName(), propertyName, Collections.nCopies(1, m), args);
} finally {
objectArrayPool.recycle(args);
}
} else {
result = false;
}
}
return result;
}
注释:(1)getSetMethod获取person对象中的setName方法
(2)根据传进来的值创建一个参数数组args
(3)调用callAppropriateMethod方法,执行setName方法
11、callAppropriateMethod()代码:
public static Object callAppropriateMethod( OgnlContext context, Object source, Object target, String methodName, String propertyName, List methods, Object[] args ) throws MethodFailedException
{
Throwable reason = null;
Object[] actualArgs = objectArrayPool.create(args.length);
try {
Method method = getAppropriateMethod( context, source, target, methodName, propertyName, methods, args, actualArgs );
if ( (method == null) || !isMethodAccessible(context, source, method, propertyName) )
{
StringBuffer buffer = new StringBuffer();
if (args != null) {
for (int i = 0, ilast = args.length - 1; i <= ilast; i++) {
Object arg = args[i];
buffer.append((arg == null) ? NULL_STRING : arg.getClass().getName());
if (i < ilast) {
buffer.append(", ");
}
}
}
throw new NoSuchMethodException( methodName + "(" + buffer + ")" );
}
return invokeMethod(target, method, actualArgs);
}
catch (NoSuchMethodException e)
{ reason = e; }
catch (IllegalAccessException e)
{ reason = e; }
catch (InvocationTargetException e)
{ reason = e.getTargetException(); }
finally {
objectArrayPool.recycle(actualArgs);
}
throw new MethodFailedException( source, methodName, reason );
}
注释:(1)形式参数List methods,这里为什么是list类型呢?也就是说这个方法可以有多个,为什么《刨根问底--ognl-get获取数据》中只有一个方法呢?
笔者的理解:java中方法重载的应用,规则:方法名称相同 方法的参数必须不同 参数个数不同 或 参数类型不同 方法的返回值类型可以相同,也可以不同。
(2)getAppropriateMethod()获取合适的方法,代码:
public static Method getAppropriateMethod( OgnlContext context, Object source, Object target, String methodName, String propertyName, List methods, Object[] args, Object[] actualArgs )
{
Method result = null;
Class[] resultParameterTypes = null;
if (methods != null) {
for (int i = 0, icount = methods.size(); i < icount; i++) {
Method m = (Method)methods.get(i);
Class[] mParameterTypes = getParameterTypes(m);
if ( areArgsCompatible(args, mParameterTypes) && ((result == null) || isMoreSpecific(mParameterTypes, resultParameterTypes)) ) {
result = m;
resultParameterTypes = mParameterTypes;
System.arraycopy(args, 0, actualArgs, 0, args.length);
for (int j = 0; j < mParameterTypes.length; j++) {
Class type = mParameterTypes[j];
if (type.isPrimitive() && (actualArgs[j] == null)) {
actualArgs[j] = getConvertedType(context, source, result, propertyName, null, type);
}
}
}
}
}
if ( result == null ) {
result = getConvertedMethodAndArgs( context, target, propertyName, methods, args, actualArgs );
}
return result;
}
getAppropriateMethod()方法中主要遍历methods中的方法,查看遍历的方法中的参数类型和传进来的值的类型是否一致。返回合适的方法。
上面的过程中找到了合适的方法了,然后通过java反射机制执行该方法invokeMethod()。