public Object invoke()

in geronimo-el_2.2_spec/src/main/java/javax/el/BeanELResolver.java [349:463]


    public Object invoke(ELContext context, Object base, Object method, Class<?>[] paramTypes, Object[] params) {
        if (context == null) {
            throw new NullPointerException("ELContext could not be nulll");
        }
        // Why static invocation is not supported
        if (base == null || method == null) {
            return null;
        }

        String methodName = ELUtils.coerceToString(method);
        if (methodName.length() == 0) {
            throw new MethodNotFoundException("The parameter method could not be zero-length");
        }
        Class<?> targetClass = base.getClass();
        if (methodName.equals("<init>") || methodName.equals("<cinit>")) {
            throw new MethodNotFoundException(method + " is not found in target class " + targetClass.getName());
        }

        if (params == null) {
            params = new Object[0];
        }

        Method targetMethod = null;
        if (paramTypes == null) {
            int paramsNumber = params.length;
            Method[] methods = targetClass.getMethods();
            for (Method m : methods) {
                if (m.getName().equals(methodName) && m.getParameterTypes().length == paramsNumber) {
                    targetMethod = m;
                    break;
                }
            }
            if (targetMethod == null) {
                for (Method m : methods) {
                    if (m.getName().equals(methodName) && m.isVarArgs() && paramsNumber >= (m.getParameterTypes().length - 1)) {
                        targetMethod = m;
                        break;
                    }
                }
            }
        } else {
            try {
                targetMethod = targetClass.getMethod(methodName, paramTypes);
            } catch (SecurityException e) {
                throw new ELException(e);
            } catch (NoSuchMethodException e) {
                throw new MethodNotFoundException(e);
            }
        }
        if (targetMethod == null) {
            throw new MethodNotFoundException(method + " is not found in target class " + targetClass.getName());
        }
        if (paramTypes == null) {
            paramTypes = targetMethod.getParameterTypes();
        }
        //Initial check whether the types and parameter values length
        if (targetMethod.isVarArgs()) {
            if (paramTypes.length - 1 > params.length) {
                throw new IllegalArgumentException("Inconsistent number between argument types and values");
            }
        } else if (paramTypes.length != params.length) {
            throw new IllegalArgumentException("Inconsistent number between argument types and values");
        }
        try {
            Object[] finalParamValues = new Object[paramTypes.length];
            //Only do the parameter conversion while the method is not a non-parameter one
            if (paramTypes.length > 0) {
                ExpressionFactory expressionFactory = null;
                if (ELUtils.isCachedExpressionFactoryEnabled()) {
                    expressionFactory = ELUtils.getCachedExpressionFactory();
                }
                if (expressionFactory == null) {
                    expressionFactory = ExpressionFactory.newInstance();
                }

                int iCurrentIndex = 0;
                for (int iLoopSize = paramTypes.length - 1; iCurrentIndex < iLoopSize; iCurrentIndex++) {
                    finalParamValues[iCurrentIndex] = expressionFactory.coerceToType(params[iCurrentIndex], paramTypes[iCurrentIndex]);
                }
                /**
                 * Not sure it is over-designed. Do not find detailed description about how the parameter values are passed if the method is of variable arguments.
                 * It might be an array directly passed or each parameter value passed one by one.
                 */
                if (targetMethod.isVarArgs()) {
                    // varArgsClassType should be an array type
                    Class<?> varArgsClassType = paramTypes[iCurrentIndex];
                    // 1. If there is no parameter value left for the variable argument, create a zero-length array
                    // 2. If there is only one parameter value left for the variable argument, and it has the same array type with the varArgsClass, pass in directly
                    // 3. Else, create an array of varArgsClass type, and add all the left coerced parameter values
                    if (iCurrentIndex == params.length) {
                        finalParamValues[iCurrentIndex] = Array.newInstance(varArgsClassType.getComponentType(), 0);
                    } else if (iCurrentIndex == params.length - 1 && varArgsClassType == params[iCurrentIndex].getClass()
                            && varArgsClassType.getClassLoader() == params[iCurrentIndex].getClass().getClassLoader()) {
                        finalParamValues[iCurrentIndex] = params[iCurrentIndex];
                    } else {
                        Object targetArray = Array.newInstance(varArgsClassType.getComponentType(), params.length - iCurrentIndex);
                        Class<?> componentClassType = varArgsClassType.getComponentType();
                        for (int i = 0, iLoopSize = params.length - iCurrentIndex; i < iLoopSize; i++) {
                            Array.set(targetArray, i, expressionFactory.coerceToType(params[iCurrentIndex + i], componentClassType));
                        }
                        finalParamValues[iCurrentIndex] = targetArray;
                    }
                } else {
                    finalParamValues[iCurrentIndex] = expressionFactory.coerceToType(params[iCurrentIndex], paramTypes[iCurrentIndex]);
                }
            }
            Object retValue = targetMethod.invoke(base, finalParamValues);
            context.setPropertyResolved(true);
            return retValue;
        }  catch (IllegalAccessException e) {
            throw new ELException(e);
        } catch (InvocationTargetException e) {
            throw new ELException(e.getCause());
        }
    }