Java8从类中检索lambda setter [英] Java8 retrieving lambda setter from class

查看:167
本文介绍了Java8从类中检索lambda setter的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为私有字段的setter获取lambda方法句柄,但由于某种原因,找不到setter。



这是我正在使用的功能接口:

  @FunctionalInterface 
public interface ISetter< T,R> {
void set(T object,R value);
}

这是用于获取setter的方法:

  public ISetter getSetter(Class clazz,String fieldName,Class fieldType)throws Throwable {

MethodHandles.Lookup caller = MethodHandles.lookup ();
MethodType setter = MethodType.methodType(Void.class,fieldType);
MethodHandle target = caller.findVirtual(clazz,computeSetterName(fieldName),setter);
MethodType func = target.type();

CallSite site = LambdaMetafactory.metafactory(
caller,
set,
MethodType.methodType(ISetter.class),
func.generic( ),
目标,
func
);

MethodHandle factory = site.getTarget();
ISetter r =(ISetter)factory.invoke();

返回r;
}

按惯例,所有设置者的名称都相同:setField(.. )。
这是我的测试类:

  public class TestEntity {

private Long id;


public TestEntity(Long id){
this.id = id;
}


public Long getId(){
return id;
}

public void setId(Long id){
this.id = id;
}
}

但是当我为id执行此方法时Long.class我得到以下异常:

 线程main中的异常java.lang.NoSuchMethodException:没有这样的方法:de.cyclonit.exercise.TestEntity.setId(Long)Void / invokeVirtual 
at java.lang.invoke.MemberName.makeAccessException(MemberName.java:871)
at java.lang.invoke.MemberName $ Factory.resolveOrFail(MemberName.java:1003)
at java.lang.invoke.MethodHandles $ Lookup.resolveOrFail(MethodHandles.java:1381)
at java.lang.invoke.MethodHandles $ Lookup.findVirtual( MethodHandles.java:859)
at de.cyclonit.exercise.AccessorFactory.getSetter(AccessorFactory.java:41)
at de.cyclonit.exercise.Main.main(Main.java:21)
引起:java.lang.NoSuchFieldError:方法解析失败
at java.lang.invoke.MethodHandleNatives.resolve(Native Method)
at java.lang.invoke.MemberName $ Factory.resolve(MemberName)的.java:975) java.lang.invoke.MemberName $ $ $ b $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $

我不明白这个错误的来源。方法void setId(Long)确实存在。






  public String computeSetterName (String fieldName){
returnset+ fieldName.substring(0,1).toUpperCase()+ fieldName.substring(1);
}

电话:

  ISetter setter = accessorFactory.getSetter(TestEntity.class,id,Long.class); 


解决方案

您的代码中存在一些错误。



首先,你使用 Void.class ,你应该使用 void.class 代替。



其次, func.generic 返回(对象,对象) )对象,你真正想要的是 func.erase ,所以保留了返回类型((Object,Object) void )。



第三,建议不要使用原始类型,我建议改为以下实现:

  public static< T,R> ISetter< T,R> getSetter(Class< T> clazz,String fieldName,
Class< R> fieldType)抛出Throwable {

MethodHandles.Lookup caller = MethodHandles.lookup();
MethodType setter = MethodType.methodType(void.class,fieldType);
MethodHandle target = caller.findVirtual(clazz,computeSetterName(fieldName),setter);
MethodType func = target.type();

CallSite site = LambdaMetafactory.metafactory(
caller,
set,
MethodType.methodType(ISetter.class),
func.erase( ),
目标,
func
);

MethodHandle factory = site.getTarget();
ISetter< T,R> r =(ISetter< T,R>)factory.invoke();

返回r;
}

这对我有用: http://ideone.com/KKx10r


I'm trying to get a lambda method handle for the setter of a private field, but for some reason, the setter cannot be found.

This is the functional interface I am using:

@FunctionalInterface
public interface ISetter<T, R> {
    void set(T object, R value);
}

And this the method used to fetch the setter:

public ISetter getSetter(Class clazz, String fieldName, Class fieldType) throws Throwable {

    MethodHandles.Lookup caller = MethodHandles.lookup();
    MethodType setter = MethodType.methodType(Void.class, fieldType);
    MethodHandle target = caller.findVirtual(clazz, computeSetterName(fieldName), setter);
    MethodType func = target.type();

    CallSite site = LambdaMetafactory.metafactory(
            caller,
            "set",
            MethodType.methodType(ISetter.class),
            func.generic(),
            target,
            func
    );

    MethodHandle factory = site.getTarget();
    ISetter r = (ISetter) factory.invoke();

    return r;
}

All setters are, by convention, named the same: "setField(...)". This is my test class:

public class TestEntity {

    private Long id;


    public TestEntity(Long id) {
        this.id = id;
    }


    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
}

But when I execute this method for "id" and "Long.class" I get the follow exception:

Exception in thread "main" java.lang.NoSuchMethodException: no such method: de.cyclonit.exercise.TestEntity.setId(Long)Void/invokeVirtual
    at java.lang.invoke.MemberName.makeAccessException(MemberName.java:871)
    at java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:1003)
    at java.lang.invoke.MethodHandles$Lookup.resolveOrFail(MethodHandles.java:1381)
    at java.lang.invoke.MethodHandles$Lookup.findVirtual(MethodHandles.java:859)
    at de.cyclonit.exercise.AccessorFactory.getSetter(AccessorFactory.java:41)
    at de.cyclonit.exercise.Main.main(Main.java:21)
Caused by: java.lang.NoSuchFieldError: method resolution failed
    at java.lang.invoke.MethodHandleNatives.resolve(Native Method)
    at java.lang.invoke.MemberName$Factory.resolve(MemberName.java:975)
    at java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:1000)
    ... 4 more

I don't understand where this error is coming from. The method "void setId(Long)" does exist.


public String computeSetterName(String fieldName) {
    return "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
}

And the call:

ISetter setter = accessorFactory.getSetter(TestEntity.class, "id", Long.class);

解决方案

There are a few mistakes in your code.

First, you are using Void.class, you should use void.class instead.

Second, func.generic returns (Object,Object)Object, what you really want is func.erase, so the return type is retained ((Object,Object)void).

Third, it advisable not to use raw types, I would propose the following implementation instead:

public static <T, R> ISetter<T, R> getSetter(Class<T> clazz, String fieldName,
        Class<R> fieldType) throws Throwable {

    MethodHandles.Lookup caller = MethodHandles.lookup();
    MethodType setter = MethodType.methodType(void.class, fieldType);
    MethodHandle target = caller.findVirtual(clazz, computeSetterName(fieldName), setter);
    MethodType func = target.type();

    CallSite site = LambdaMetafactory.metafactory(
            caller,
            "set",
            MethodType.methodType(ISetter.class),
            func.erase(),
            target,
            func
    );

    MethodHandle factory = site.getTarget();
    ISetter<T, R> r = (ISetter<T, R>) factory.invoke();

    return r;
}

Which works for me: http://ideone.com/KKx10r

这篇关于Java8从类中检索lambda setter的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆