具有一般非空 return 过滤器的 MethodHandle?
MethodHandle with general non-void return filter?
我正在尝试建立一个 MethodHandle
,它具有针对 return 值的通用过滤器,方法是使用 MethodHandles.filterReturnValue()
来完成工作。
我遇到的问题是我不知道(也不关心)return 类型,所以我希望只连接一个 Object myfilter(Object obj)
作为 MethodHandle
过滤 return 个对象。然而,这在 MethodHandles.filterReturnValue()
调用中显然是不允许的。
这是我希望能奏效的(但没有奏效)...
package invoke;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.util.Arrays;
public class MethodHandleReturnExample
{
public static void main(String[] args) throws Throwable
{
MethodHandles.Lookup lookup = MethodHandles.lookup();
Testcase test = new Testcase();
MethodHandle onCount = findMethodByName(lookup, test, "onCount");
MethodHandle onNada = findMethodByName(lookup, test, "onNada");
MethodHandle onText = findMethodByName(lookup, test, "onText");
onNada.invoke("hello");
onText.invoke("world");
onCount.invoke();
onCount.invoke();
onCount.invoke();
}
private static MethodHandle findMethodByName(MethodHandles.Lookup lookup, Object obj, String methodName) throws IllegalAccessException, NoSuchMethodException
{
Method method = Arrays.stream(obj.getClass().getDeclaredMethods())
.filter(m -> m.getName().equalsIgnoreCase(methodName))
.findFirst().get();
MethodHandle handle = lookup.unreflect(method);
handle = handle.bindTo(obj);
if (handle.type().returnType() != Void.TYPE)
{
MethodHandle returnFilter = lookup.findVirtual(Util.class, "filter", MethodType.methodType(Object.class,Object.class));
returnFilter = returnFilter.bindTo(new Util());
handle = MethodHandles.filterReturnValue(handle, returnFilter);
}
return handle;
}
public static class Testcase
{
int count = 0;
public int onCount()
{
int ret = ++count;
System.out.printf("onCount() : %d%n", ret);
return ret;
}
public void onNada(String msg)
{
System.out.printf("onNada(%s)%n", msg);
}
public String onText(String msg)
{
System.out.printf("onText(%s)%n", msg);
return "[text:" + msg + "]";
}
}
public static class Util
{
public Object filter(Object obj)
{
System.out.printf("# filter((%s) %s)%n", obj.getClass().getName(), obj);
return obj;
}
}
}
看来 MethodHandles.filterReturnValue()
不适合这个目的。
我当时希望我可以制作一个 MethodHandle
来调用另一个 MethodHandle
,但这开始变得复杂了。
例如:
public Object filter(MethodHandle handle, Object ... args)
{
Object ret = handle.invoke(args);
System.out.printf("# filter((%s) %s)%n", ret.getClass().getName(), ret);
return ret;
}
我试图理解 MethodHandleProxies
or even LamdaMetafactory
,但是从网上找到的 javadoc 和少量示例很难理解它们。
filterReturnValue
将调用 target
句柄,如果它使用 invokeExact
,因此 return 类型必须完全匹配。
因此您必须将 return 类型调整为 Object
。最简单的方法是使用 asType
(这也会自动框住 int
):
if (handle.type().returnType() != Void.TYPE) {
handle = handle.asType(handle.type().changeReturnType(Object.class)); // <---
MethodHandle returnFilter = lookup.findVirtual(Util.class, "filter",
MethodType.methodType(Object.class, Object.class));
returnFilter = returnFilter.bindTo(new Util());
handle = MethodHandles.filterReturnValue(handle, returnFilter);
}
我正在尝试建立一个 MethodHandle
,它具有针对 return 值的通用过滤器,方法是使用 MethodHandles.filterReturnValue()
来完成工作。
我遇到的问题是我不知道(也不关心)return 类型,所以我希望只连接一个 Object myfilter(Object obj)
作为 MethodHandle
过滤 return 个对象。然而,这在 MethodHandles.filterReturnValue()
调用中显然是不允许的。
这是我希望能奏效的(但没有奏效)...
package invoke;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.util.Arrays;
public class MethodHandleReturnExample
{
public static void main(String[] args) throws Throwable
{
MethodHandles.Lookup lookup = MethodHandles.lookup();
Testcase test = new Testcase();
MethodHandle onCount = findMethodByName(lookup, test, "onCount");
MethodHandle onNada = findMethodByName(lookup, test, "onNada");
MethodHandle onText = findMethodByName(lookup, test, "onText");
onNada.invoke("hello");
onText.invoke("world");
onCount.invoke();
onCount.invoke();
onCount.invoke();
}
private static MethodHandle findMethodByName(MethodHandles.Lookup lookup, Object obj, String methodName) throws IllegalAccessException, NoSuchMethodException
{
Method method = Arrays.stream(obj.getClass().getDeclaredMethods())
.filter(m -> m.getName().equalsIgnoreCase(methodName))
.findFirst().get();
MethodHandle handle = lookup.unreflect(method);
handle = handle.bindTo(obj);
if (handle.type().returnType() != Void.TYPE)
{
MethodHandle returnFilter = lookup.findVirtual(Util.class, "filter", MethodType.methodType(Object.class,Object.class));
returnFilter = returnFilter.bindTo(new Util());
handle = MethodHandles.filterReturnValue(handle, returnFilter);
}
return handle;
}
public static class Testcase
{
int count = 0;
public int onCount()
{
int ret = ++count;
System.out.printf("onCount() : %d%n", ret);
return ret;
}
public void onNada(String msg)
{
System.out.printf("onNada(%s)%n", msg);
}
public String onText(String msg)
{
System.out.printf("onText(%s)%n", msg);
return "[text:" + msg + "]";
}
}
public static class Util
{
public Object filter(Object obj)
{
System.out.printf("# filter((%s) %s)%n", obj.getClass().getName(), obj);
return obj;
}
}
}
看来 MethodHandles.filterReturnValue()
不适合这个目的。
我当时希望我可以制作一个 MethodHandle
来调用另一个 MethodHandle
,但这开始变得复杂了。
例如:
public Object filter(MethodHandle handle, Object ... args)
{
Object ret = handle.invoke(args);
System.out.printf("# filter((%s) %s)%n", ret.getClass().getName(), ret);
return ret;
}
我试图理解 MethodHandleProxies
or even LamdaMetafactory
,但是从网上找到的 javadoc 和少量示例很难理解它们。
filterReturnValue
将调用 target
句柄,如果它使用 invokeExact
,因此 return 类型必须完全匹配。
因此您必须将 return 类型调整为 Object
。最简单的方法是使用 asType
(这也会自动框住 int
):
if (handle.type().returnType() != Void.TYPE) {
handle = handle.asType(handle.type().changeReturnType(Object.class)); // <---
MethodHandle returnFilter = lookup.findVirtual(Util.class, "filter",
MethodType.methodType(Object.class, Object.class));
returnFilter = returnFilter.bindTo(new Util());
handle = MethodHandles.filterReturnValue(handle, returnFilter);
}