mercredi 9 mars 2016

How to use the Lambda MetaFactory, or Method Handle rather than reflection when trying to invoke a method?

I have a method that is suppose to take in the classname, argument, and method name as parameters and invoke the method depending on which class it finds it in. The method:

private static boolean runKeyword(ArrayList<String> argList, Class<?> className, String methodName) {
        int argListSize = 0;
        if(argList != null)
            argListSize = argList.size();
        boolean keywordResult = false;
        Parameter[] parameters;
        Class<?>[] paramType;
        List<String> methodArguments;
//      Object[] methodArguments;
        int methodParameters = 0;
        Class<?>[] argTypes = {SoftAssertion.class};
        Constructor<?> constructor = null;
        Object classInstance = null;
        try {
            constructor = className.getDeclaredConstructor(argTypes);
        } catch (NoSuchMethodException | SecurityException e2) {
            e2.printStackTrace();
        }
        Object[] arguments = {myAssert};
        try {
            classInstance = constructor.newInstance(arguments);
        } catch (InstantiationException | IllegalAccessException 
                | IllegalArgumentException | InvocationTargetException e2) {
            e2.printStackTrace();
        }
        Method[] methods = className.getDeclaredMethods();
        for(Method meth: methods){
            if(meth.getName().equalsIgnoreCase(methodName)){
                parameters = meth.getParameters();
                methodParameters = parameters.length;
                methodArguments = new ArrayList<>();
//              methodArguments = new Object[methodParameters];
                paramType = new Class<?>[methodParameters];
                Class<?>[] types = meth.getParameterTypes();
                if(argListSize != methodParameters){
                    myAssert.setGblPassFailMessage("fail", "Expected " + methodParameters + " argument found "
                                    + argListSize + " arguments");
                    return false;
                }
                 for(int i=0; i<types.length;i++){
                     paramType[i] = types[i];
                 }
                 if(methodParameters != 0){
                     for(int i=0; i<argListSize; i++){
//                       methodArguments[i] = (String) argList.get(i);
                         methodArguments.add((String) argList.get(i));
                     }
                 }
                try {
                    MethodType mt=MethodType.methodType(boolean.class, paramType);
                    MethodHandles.Lookup caller = MethodHandles.lookup();
                    MethodHandle handle=caller.findVirtual(className, meth.getName(), mt);
                    /*
                     * Trying to invoke using lambdaMetaFactory
                     */
                    MethodType methodType = MethodType.methodType(boolean.class);
                    MethodType invokedType = MethodType.methodType(BooleanSupplier.class);
                    /*
                     * Throws java.lang.invoke.LambdaConversionException: Incorrect number of parameters for instance method 
                     * invokeVirtual com.grainger.Automation.Utilities.navigateToUrl:(String)boolean; 0 captured parameters, 
                     * 0 functional interface method parameters, 1 implementation parameters
                     */
                    CallSite site = LambdaMetafactory.metafactory(caller, "getAsBoolean", invokedType, methodType, handle, methodType);

                    MethodHandle factory = site.getTarget();
                    BooleanSupplier r = (BooleanSupplier) factory.invoke();
                    System.out.println(r.getAsBoolean());
                    /*
                     * Trying to invoke using Method Handle
                     */
                    /*
                     * Trying to invoke the method handle here, but it fails with:
                     * java.lang.invoke.WrongMethodTypeException: cannot convert MethodHandle(Utilities,String)boolean to (Object)Object
                     */
                    System.out.println(handle.invokeWithArguments(methodArguments.toArray())); //Output B
                    /*
                     * Invoking it directly with a string as an argument throws this execption:
                     * com.sun.jdi.InvalidTypeException: Generated value (java.lang.String) is not compatible with declared type (java.lang.Object[]). occurred invoking method.
                     */
                    System.out.println(handle.invokeExact("www.google.com"));
//                  keywordResult = (Boolean) handle.invoke("www.google.com");
                    /*
                     * Using the regular Reflections API, the method invoke works but is slow
                     */
//                  keywordResult = (Boolean) meth.invoke(classInstance, methodArguments); //Regular refection call to invoke the function
                    break;
                } catch (Throwable e) {
                    System.out.println(e.getMessage());
                    keywordResult = false;
                }
            }
        }

        if(keywordResult || argListSize == 0){
            myAssert.assertTrue(keywordResult);
            return true;
        }else{
            myAssert.assertTrue(false);
            return false;
        }
    }

The method I'm trying to invoke is located in a separate class within the same package. This is method definition:

public boolean navigateToUrl(String strUrl) {
return true;
}

When I try to invoke the function using the lambdametafactory, I get a LambdaConversionException. When I try to invoke the method using method handle, I get the exception Java.lang.invoke.WrongMethodTypeException when invoking with arguments and sending in an ArrayList<>. I get a com.sun.jdi.InvalidTypeException when doing invokExact with a String as the argument. All this is also listed above in the comments.

I'm not able to figure out what I'm doing wrong here. Any help would be greatly appreciated! If their is anything I'm missing from the code, please let me know!





Aucun commentaire:

Enregistrer un commentaire