public int arity(ELContext elctx) { if (node instanceof ELNode.LAMBDA) { return ((ELNode.LAMBDA) node).vars.length; } MethodInfo info = node.getMethodInfo(getContext(elctx)); if (info != null && info.getParamTypes() != null) { return info.getParamTypes().length; } else { return -1; } }
/** * This method wraps a <code>MethodExpression</code> in a <code>Method</code> which can be * statically invoked. * * <p>Since Method is a final class with only a non-public constructor, various reflective tricks * have been used to create an instance of this class and make sure it calls the given method * expression. It has been tested on the Sun/Oracle JDK versions 6 and 7, and it should work on * OpenJDK 6 and 7 as well. Other JDKs might not work. * * @param context the context used for evaluation of the method expression when it's invoked * later. NOTE, this reference is retained by the returned method. * @param methodExpression the method expression to be wrapped * @return a Method instance that when invoked causes the wrapped method expression to be invoked. */ public static Method methodExpressionToStaticMethod( final ELContext context, final MethodExpression methodExpression) { final MethodInfo methodInfo = methodExpression.getMethodInfo(FacesContext.getCurrentInstance().getELContext()); try { // Create a Method instance with the signature (return type, name, // parameter types) corresponding // to the method the MethodExpression references. final Constructor<Method> methodConstructor = Method.class.getDeclaredConstructor( Class.class, String.class, Class[].class, Class.class, Class[].class, int.class, int.class, String.class, byte[].class, byte[].class, byte[].class); methodConstructor.setAccessible(true); final Method staticMethod = methodConstructor.newInstance( null, methodInfo.getName(), methodInfo.getParamTypes(), methodInfo.getReturnType(), null, 0, 0, null, null, null, null); // The Sun/Oracle/OpenJDK Method makes use of a private delegator // called MethodAccessor. // Though specific to those JDKs, this is what we can use to let our // Method instance execute something // we want. (simply overriding the invoke method would be much // better, but unfortunately Method is final) final Class<?> methodAccessorClass = Class.forName("sun.reflect.MethodAccessor"); // Create a proxy for our MethodAccessor, so we don't have to // reference the actual type at compile-time. final Object MethodAccessor = Proxy.newProxyInstance( Method.class.getClassLoader(), new Class[] {methodAccessorClass}, new InvocationHandler() { @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { Object[] params = null; if (args != null && args.length > 1) { // args[0] // should // be // the // Object // on // which // the // method // is // to // be // invoked // (null // in // case // of // static // call) // args[1] // should // be // the // parameters // for // the // method // invocation // (possibly // empty) params = (Object[]) args[1]; } else { params = Hacks.EMPTY_PARAMETERS; } return methodExpression.invoke(context, params); } }); final Method setMethodAccessor = Method.class.getDeclaredMethod("setMethodAccessor", methodAccessorClass); setMethodAccessor.setAccessible(true); setMethodAccessor.invoke(staticMethod, MethodAccessor); // Another private implementation detail of the Sun/Oracle/OpenJDK // Method - unless override is set // to true, a couple of nasty language checks are done before // invoking the MethodAccessor final Field override = AccessibleObject.class.getDeclaredField("override"); override.setAccessible(true); override.set(staticMethod, true); return staticMethod; } catch (final Exception e) { throw new IllegalStateException(e); } }