java - Types in a LambdaMetaFactory -


i exception when call metafactory. says:

java.lang.invoke.lambdaconversionexception:     incorrect number of parameters instance method         invokevirtual my.executetest$aprocess.step_1:()boolean;     0 captured parameters,      0 functional interface method parameters,      0 implementation parameters 

i not understand documentation of lambdametafactory.metafactory. have problems figuring out correct parameters:

  • methodhandles.lookup caller -- thats easy
  • string invokedname -- here
  • methodtype invokedtype -- whats this?
  • methodtype sammethodtype -- err... not sure here
  • methodhandle implmethod -- that's fine
  • methodtype instantiatedmethodtype -- whats this, again? second time?

so boils down differences between:

  • methodtype invokedtype
  • methodtype sammethodtype
  • methodtype instantiatedmethodtype

my code this:

package my;  import java.lang.invoke.*; import java.lang.reflect.method;  public class execute {    public interface processbase {};    @functionalinterface   public interface step {     boolean apply();   }    public step getmethodfromstepid(processbase process, int stepid) {     try {       // standard reflection stuff       final methodhandle unreflect = caller.unreflect(method);       final string mname = "step_"+stepid;       // new java8 method reference stuff       final method method = process.getclass().getmethod(mname);       final methodtype type=methodtype.methodtype(boolean.class);       final methodtype steptype=methodtype.methodtype(step.class);       final methodhandles.lookup caller = methodhandles.lookup();       final callsite site = lambdametafactory.metafactory(           caller, "apply", steptype, type, unreflect, type); // damn       // convert site method reference       final methodhandle factory = site.gettarget();       final step step = (step) factory.invoke();       return step;     } catch (throwable throwable) {       throw new runtimeexception(throwable);     }   } } 

with tests

package my;  import org.junit.test; import static org.junit.assert.*;  public class executetest {    private class aprocess implements execute.processbase {     public boolean step_1() { return true; }     public boolean step_2() { return false; }   }    @test   public void getmethodfromstepid() throws exception {     final aprocess process = new aprocess();     {       final execute.step methodref = instance.getmethodfromstepid(process, 1);       final boolean result = methodref.apply();       asserttrue(result);     }     {       final execute.step methodref = instance.getmethodfromstepid(process, 2);       final boolean result = methodref.apply();       assertfalse(result);     }   }    private final execute instance = new execute();  } 

the first 3 parameters not special lambda expressions, standard arguments bootstrap methods of invokedynamic instruction. lookup parameter encapsulates caller’s context, invokedname , invokedtype parameters represent name , type of invokedynamic instruction.

it’s bootstrap method assign more semantic it. since in context, purpose of instruction produce lambda expression instance, consume captured values , produce interface instance. invokedtype have parameter types reflecting type of captured values or parameter-less non-capturing lambdas , have return type matching desired functional interface. invokedname used specify functional interface’s method name, unusual it’s not invoked here, since invoked name has no other meaning otherwise, parameter reused here.

the sammethodtype signature of functional interface’s method implement (on byte code level), identical instantiatedmethodtype long as, e.g. generics not involved. otherwise, sammethodtype subject type erasure whereas instantiatedmethodtype incorporates actual type arguments, e.g. implement function<string,integer>

  • invokedtype have return type of function
  • sammethodtype (object)object
  • instantiatedmethodtype (string)integer

note specific case, types correct, since want invoke target method on provided process instance, have bind lambda instance (you didn’t try). unfortunately, didn’t make clear kind of actual problem have (i.e. getting lambdaconversionexception) in question, didn’t notice problem before.

as said above, invokedtype must contain types of values capture parameter types. then, have pass actual process instance invoke call. name suggests, invokedtype must match 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 method reference             final methodhandle factory = site.gettarget();             // pass value bind , functional interface instance             final step step = (step)factory.invoke(process);             return step;       } catch (throwable throwable) {             throw new runtimeexception(throwable);       } } 

Comments

Popular posts from this blog

unity3d - Rotate an object to face an opposite direction -

angular - Is it possible to get native element for formControl? -

javascript - Why jQuery Select box change event is now working? -