CallSite lambdaFactory = LambdaMetafactory.metafactory(
lookup,
"call",
MethodType.methodType(BiConsumer.class),
MethodType.methodType(void.class,Long.class),
lookup.findVirtual(CallClass.class, "call",
MethodType.methodType(void.class,Long.class)),
MethodType.methodType(void.class));
lambdaFactory.getTarget().invoke(callId);
private void call(Long callId){
---
}
I am getting this exception java.lang.invoke.LambdaConversionException: Incorrect number of parameters for instance method invokeVirtual call:()void; 0 captured parameters, 0 functional interface method parameters, 0 implementation parameters
There is almost everything wrong in this invocation:
CallSite lambdaFactory = LambdaMetafactory.metafactory(
lookup,
"call",
this must be the name of the interface method needed to be implemented. ForBiConsumer
, this is"accept"
.MethodType.methodType(BiConsumer.class),
this is the invokedType which must match theinvoke
call at (10).MethodType.methodType(void.class,Long.class),
this is the signature of the interface method to implement at the bytecode level, i.e. after type erasure. ForBiConsumer
, this is alwaysMethodType.methodType(void.class, Object.class, Object.class)
.lookup.findVirtual(CallClass.class, "call",
MethodType.methodType(void.class,Long.class)),
MethodType.methodType(void.class)
this is the specialization of the interface or identical to (5) when the interface is not generic. In either case, the number of parameters must match with (5). For your case, you likely want match the target method, so it must beMethodType.methodType(void.class, CallClass.class, Long.class)
.);
lambdaFactory.getTarget().invoke(callId);
theinvoke
call must match the invokedType signature specified in (4). The specified arguments are the values to be captured. Since you’ve chosen to implementBiConsumer
, which has the same functional signature as your target method, there is no use for an additional value.The biggest problem is the mismatch between (4) and (10), as it makes it unclear what you actually want to achieve. Do you want to capture an existing
callId
asinvoke(callId)
suggests or do you want to create a non-capturing function, as the invokedType argument and the choice ofBiConsumer
suggest?For a straight-forward
BiConsumer
generation, the fixed code would look like:If you want to capture an existing
callId
, you would have to change the functional interface to a type not expecting a second argument. Further, you’d need an adapter, because theLambdaMetafactory
expects captured arguments first and the interface method arguments afterwards. So, since this is not supported directly, the simplest solution is to generate aBiConsumer<CallClass,Long>
as above, followed byConsumer<CallClass> c = cc -> bc.apply(cc, callId);
, capturing the existingcallId
.Only if you also have an already existing
CallClass
instance you want to bind, you can do it directly: