Transform Method from file into LambdaExpresion

I'm trying to transform a Method (read from a file) into a lambda expression, so I can measure the time needed to execute that Method ignoring the slow Method.invoke(...) function.

I've been trying to accomplish my objective using LambdaMetafactory, but to be honest I have read so many questions and explanations about how to do this that I don't even know what I'm doing anymore.

Assuming that parameters and the method are well constructed and (here's the tricky part) that I have to deal dynamically with multiple options involving different number and types of parameters:

Object[] parameters = ...;
Method metodin = anotherClass.getMethod();

And the interface (sorry for the name, I'll change it later):

@FunctionalInterface
interface loadedMethod {
    Object execute(Object[] params);
}

Here's the code that tries to execute the method using a lambda:

MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh = lookup.unreflect(metodin);

CallSite callsite = LambdaMetafactory.metafactory(
       lookup,
       "execute",
       MethodType.methodType(loadedMethod.class),
       mh.type(),
       mh,
       mh.type()
);
loadedMethod loadedMethod = (loadedMethod) callsite.getTarget().invokeExact();
System.out.println("OUTPUT: " + loadedMethod.execute(parameters)); //Error occurs here

I've read this post and I don't understand what I'm doing fine and wrong. Can you help me please?

[EDIT] The current error is:

java.lang.invoke.LambdaConversionException: Incorrect number of parameters for static method invokeStatic Example.myFunction:(int[],int,int)int; 1 captured parameters, 3 functional interface method parameters, 3 implementation parameters
    at java.base/java.lang.invoke.AbstractValidatingLambdaMetafactory.validateMetafactoryArgs(AbstractValidatingLambdaMetafactory.java:214)
    at java.base/java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:328)
    at optimex.ObjectCallable.call(ObjectCallable.java:60)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at java.base/java.lang.Thread.run(Thread.java:834)

Upvotes: 0

Views: 270

Answers (1)

Johannes Kuhn
Johannes Kuhn

Reputation: 15163

Ahh, yeah.

You call metalambdafactory wrong:

The concept of the meta lambda factory is that it creates a lambda factory.
You then use the factory to create the actual instance of the lambda.

The first MethodType is for the factory - in your case you said "capture an Object[].
You probably don't want to capture anything - so the right MethodType is methodType(loadedMethod.class).

CallSite callsite = LambdaMetafactory.metafactory(
       lookup,
       "execute",
       MethodType.methodType(loadedMethod.class),
       mh.type(),
       mh,
       mh.type()
);

You invoke the resulting MethodHandle with invokeWithArguments.
As the factory doesn't need the additional arguments, you should not pass them:

loadedMethod loadedMethod = (loadedMethod) callsite.getTarget().invokeExact();

Upvotes: 1

Related Questions