加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

LambdaMetafactory的Java访问bean方法

发布时间:2020-12-15 07:38:29 所属栏目:Java 来源:网络整理
导读:我的问题与 Explicit use of LambdaMetafactory密切相关 在该线程中,提供了一些非常好的示例来使用LambdaMetafactory来访问类的静态方法;但是,我想知道访问现有bean实例的非静态字段的等效代码是什么.似乎很难找到一个例子,我所执行的每一次尝试都以非工作代
我的问题与 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,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,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,MethodType.methodType(Object.class,SimpleBean.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,getter);
CallSite site = LambdaMetafactory.metafactory(caller,// include types of the values to bind:
    MethodType.methodType(Supplier.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,getter);
MethodType func=target.type();
CallSite site = LambdaMetafactory.metafactory(caller,"apply",MethodType.methodType(Function.class),func.generic(),func);

MethodHandle factory = site.getTarget();
Function r = (Function)factory.invoke();
assertEquals( "myCustomObject",r.apply(simpleBeanInstance));

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读