我在运行时收到要用作biPredicate的函数的名称。我想传递这个biPredicate并进行评估,基本上过滤以获得结果。 以下是我定义biPredicates的实用程序。我尝试使用MethodHandle和Lambda函数。当我使用
new FilterUtility().execute("genericFilter");
我得到了java.lang.AbstractMethodError
public class FilterUtility {
public void execute(String filterName) throws Throwable {
ActualBean beanObject = ActualBean.builder().param1("true").param2("false").build();
MethodType methodType = MethodType.methodType(boolean.class, Object.class, Object.class);
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle handle = lookup.findStatic(FilterUtility.class, filterName, methodType);
BiPredicate<Object, Object> f = (BiPredicate<Object, Object>) LambdaMetafactory.metafactory(lookup,
"test",
MethodType.methodType(BiPredicate.class),
methodType.generic(),
handle,
methodType)
.getTarget()
.invokeExact();
resolve(beanObject, new HashMap<>(), f);
}
public static <SourceObject, TemplateObject> Map<String, String> resolve(SourceObject src,
TemplateObject template,
BiPredicate<SourceObject, TemplateObject> p) {
if (p.test(src, template))
return new HashMap<>();
return null;
}
public static <SourceObject, TemplateObject> boolean genericFilter(SourceObject x, TemplateObject y) {
ObjectMapper ob = new ObjectMapper();
Map<String, Object> source = ob.convertValue(x, Map.class);
Map<String, Object> template = ob.convertValue(y, Map.class);
for (Map.Entry<String, Object> entry : template.entrySet()) {
if (!source.get(entry.getKey()).equals(entry.getValue()))
return false;
}
return true;
}
}
当我将执行的执行更改为以下时,我不会得到例外。
public void execute(String filterName) throws Throwable {
ActualBean beanObject = ActualBean.builder().param1("true").param2("false").build();
resolve(beanObject, new HashMap<>(), FilterUtility::genericFilter); }
这让我相信我试图找到具有名称的函数并将其作为biPredicate发送时出现问题。
答案 0 :(得分:2)
您正在调用方法methodType.generic()
,它将使用java.lang.Object
替换所有参数类型和返回类型,包括基本类型。因此,您正在将目标方法的签名(Object,Object)->boolean
转换为(Object,Object)->Object
,从而有效地创建一个方法Object test(Object,Object)
的类,该方法将调用您的目标方法并将结果打包。
lambda metafactory不检查这种类型不匹配。因此,当您尝试在该生成的类上调用BiPredicate
的方法boolean test(Object,Object)
时,将抛出错误。
使用的正确方法是methodType.erase()
,它将用java.lang.Object
替换所有引用类型,但保持原始类型不变。虽然,在这种特定情况下,您根本不需要转换方法类型,因为目标方法的类型已经是(Object,Object)->boolean
,所以只需用methodType.generic()
替换methodType
也可以