Types in a LambdaMetaFactory

后端 未结 1 1607
孤独总比滥情好
孤独总比滥情好 2021-02-20 16:59

I get an exception when I call metafactory. It says:

java.lang.invoke.LambdaConversionException:
    Incorrect number of parameters for instance met         


        
1条回答
  •  名媛妹妹
    2021-02-20 17:34

    The first three parameters are not special to lambda expressions, but standard arguments to bootstrap methods of invokedynamic instruction. The lookup parameter encapsulates the caller’s context, the invokedName and invokedType parameters represent the name and type of the invokedynamic instruction.

    It’s up to the bootstrap method to assign more semantic do it. Since in this context, the purpose of this instruction is produce a lambda expression instance, it will consume captured values and produce an interface instance. So the invokedType will have parameter types reflecting the type of captured values or be parameter-less for non-capturing lambdas and have a return type matching the desired functional interface. The invokedName is used to specify the functional interface’s method name, which is unusual as it’s not actually invoked here, but since the invoked name has no other meaning otherwise, this parameter is reused here.

    The samMethodType is the signature of the functional interface’s method to implement (on the byte code level), which is identical to instantiatedMethodType as long as, e.g. Generics is not involved. Otherwise, samMethodType will be subject to type erasure whereas instantiatedMethodType incorporates the actual type arguments, e.g. to implement a Function

    • invokedType will have a return type of Function
    • samMethodType will be (Object)Object
    • instantiatedMethodType will be (String)Integer

    Note that for your specific case, the types are basically correct, but since you want to invoke the target method on the provided process instance, you have to bind it to the lambda instance (you didn’t even try). Unfortunately, you didn’t make clear what kind of actual problem you have (i.e. that you are getting a LambdaConversionException) in your question, so I didn’t notice the problem before.

    As said above, the invokedType must contain the types of the values to capture as parameter types. Then, you have to pass the actual process instance to the invoke call. As the name suggests, invokedType must match the type of invoke:

    public Step getMethodFromStepid(ProcessBase process, int stepid) {
        try {
                // standard reflection stuff
                final String mname = "step_"+stepid;
                final Method method = process.getClass().getMethod(mname);
                // new java8 method reference stuff
                final MethodType type=MethodType.methodType(Boolean.class);
                // invokedType: bind process, generate Step
                final MethodType stepType=MethodType.methodType(Step.class,process.getClass());
                final MethodHandles.Lookup caller = MethodHandles.lookup();
                final MethodHandle unreflect = caller.unreflect(method);
                final CallSite site = LambdaMetafactory.metafactory(
                    caller, "apply", stepType, type, unreflect, type);
                // convert site to my method reference
                final MethodHandle factory = site.getTarget();
                // pass the value to bind and get the functional interface instance
                final Step step = (Step)factory.invoke(process);
                return step;
          } catch (Throwable throwable) {
                throw new RuntimeException(throwable);
          }
    }
    

    0 讨论(0)
提交回复
热议问题