我的问题与Explicit use of 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()":
@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());
}
每次尝试都会产生不同的负面结果,我真的希望有人帮助我让至少一项测试工作正常。
答案 0 :(得分:20)
如果要将值绑定到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));