dimanche 19 novembre 2017

How to pass a function as predicate to another function, When name of the predicate function is received at RunTime?

I receive the name of the function to be used as biPredicate at runtime. I want to pass around this biPredicate and evaluate, basically filter to get results. Following is my utility that defines biPredicates. I tried utilizing MethodHandle and Lambda Functions. When I use

new FilterUtility().execute("genericFilter");

I get java.lang.UnsupportedOperationException: MethodHandle.invokeExact cannot be invoked reflectively

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;
}
}

When I change implementation of execute to following, I dont get exceptions.

public void execute(String filterName) throws Throwable {
    ActualBean beanObject = ActualBean.builder().param1("true").param2("false").build();
    resolve(beanObject, new HashMap<>(), FilterUtility::genericFilter); }

This makes me believe that there is something wrong with the way I am trying to find the function with name and send it as a biPredicate.





Aucun commentaire:

Enregistrer un commentaire