LambdaMetafactory的Java访问bean方法

我的问题与该线程中显式使用LambdaMetafactory密切相关,提供了一些非常好的示例来使用LambdaMetafactory访问类的静态方法; 但是,我想知道访问现有bean实例的非静态字段的等效代码是什么。 似乎很难找到一个例子,我执行的每一次尝试都以非工作代码结束。

这是bean代码:

class SimpleBean { private Object obj= "myCustomObject"; private static Object STATIC_OBJECT = "myCustomStaticObject"; public Object getObj() { return obj; } public void setObj(final Object obj) { this.obj = obj; } public static Object getStaticObj() { return STATIC_OBJECT; } public static void setStaticObj(final Object obj) { STATIC_OBJECT = obj; } } 

这是一个成功访问静态方法“getStaticObj()”的工作unit testing:

  @Test public void accessStaticMethod() throws Throwable { MethodHandles.Lookup caller = MethodHandles.lookup(); Method reflected = SimpleBean.class.getDeclaredMethod("getStaticObj"); MethodHandle methodHandle = caller.unreflect(reflected); CallSite site = LambdaMetafactory.metafactory(caller, "get", MethodType.methodType(Supplier.class), MethodType.methodType(Object.class), methodHandle, MethodType.methodType(Object.class)); MethodHandle factory = site.getTarget(); Supplier r = (Supplier) factory.invoke(); assertEquals( "myCustomStaticObject", r.get()); } 

现在,我尝试访问非静态“getObj()”方法失败:

  @Test public void accessNonStaticMethodTestOne() throws Throwable { SimpleBean simpleBeanInstance = new SimpleBean(); MethodHandles.Lookup caller = MethodHandles.lookup(); MethodHandle methodHandle = caller.bind(simpleBeanInstance, "getObj", MethodType.methodType(Object.class)); assertEquals("myCustomObject", methodHandle.invoke()); // This test fails here with exception: // java.lang.IllegalArgumentException: not a direct method handle CallSite site = LambdaMetafactory.metafactory(caller, "get", MethodType.methodType(Supplier.class), MethodType.methodType(Object.class), methodHandle, MethodType.methodType(Object.class)); MethodHandle factory = site.getTarget(); Supplier r = (Supplier) factory.invoke(); assertEquals( "myCustomObject", r.get()); } @Test public void accessNonStaticMethodTwo() throws Throwable { SimpleBean simpleBeanInstance = new SimpleBean(); MethodHandles.Lookup caller = MethodHandles.lookup(); Method reflected = SimpleBean.class.getDeclaredMethod("getObj"); MethodHandle methodHandle = caller.unreflect(reflected); // This test fails here with exception: // java.lang.invoke.LambdaConversionException: Incorrect number of parameters CallSite site = LambdaMetafactory.metafactory(caller, "get", MethodType.methodType(Supplier.class), MethodType.methodType(Object.class), methodHandle, MethodType.methodType(Object.class)); MethodHandle factory = site.getTarget(); factory = factory.bindTo(simpleBeanInstance); Supplier r = (Supplier) factory.invoke(); assertEquals( "myCustomObject", r.get()); } @Test public void accessNonStaticMethodThree() throws Throwable { SimpleBean simpleBeanInstance = new SimpleBean(); MethodHandles.Lookup caller = MethodHandles.lookup(); Method reflected = SimpleBean.class.getDeclaredMethod("getObj"); MethodHandle methodHandle = caller.unreflect(reflected); CallSite site = LambdaMetafactory.metafactory(caller, "get", MethodType.methodType(Supplier.class), MethodType.methodType(Object.class, SimpleBean.class), methodHandle, MethodType.methodType(Object.class, SimpleBean.class)); MethodHandle factory = site.getTarget(); //This test fails here with exception: // java.lang.IllegalArgumentException: no leading reference parameter: spike.LambdaBeanAccessAtRuntimeTest$SimpleBean@4459eb14 factory = factory.bindTo(simpleBeanInstance); Supplier r = (Supplier) factory.invoke(); assertEquals( "myCustomObject", r.get()); } 

每次尝试都有不同的负面结果,我真的希望有人帮助我让至少一项测试工作正常。

如果要将值绑定到lamba,则必须将这些参数包含在invokedtype签名中:

 SimpleBean simpleBeanInstance = new SimpleBean(); MethodHandles.Lookup caller = MethodHandles.lookup(); MethodType getter=MethodType.methodType(Object.class); MethodHandle target=caller.findVirtual(SimpleBean.class, "getObj", getter); CallSite site = LambdaMetafactory.metafactory(caller, "get", // include types of the values to bind: MethodType.methodType(Supplier.class, SimpleBean.class), getter, target, getter); MethodHandle factory = site.getTarget(); factory = factory.bindTo(simpleBeanInstance); Supplier r = (Supplier) factory.invoke(); assertEquals( "myCustomObject", r.get()); 

您可以使用以bean作为参数的Function来代替绑定值:

 SimpleBean simpleBeanInstance = new SimpleBean(); MethodHandles.Lookup caller = MethodHandles.lookup(); MethodType getter=MethodType.methodType(Object.class); MethodHandle target=caller.findVirtual(SimpleBean.class, "getObj", getter); MethodType func=target.type(); CallSite site = LambdaMetafactory.metafactory(caller, "apply", MethodType.methodType(Function.class), func.generic(), target, func); MethodHandle factory = site.getTarget(); Function r = (Function)factory.invoke(); assertEquals( "myCustomObject", r.apply(simpleBeanInstance));