Quantcast
Channel: Active questions tagged methodhandle - Stack Overflow
Viewing all articles
Browse latest Browse all 36

LambdaMetaFactory with Generic Static Methods?

$
0
0

So I'm creating a library that allows users to pass a Class<?> and collect all static methods with a specific annotation (and other criteria, such as a certain parameter count and types) and convert them into lambda FunctionalInterfaces that my library will use internally for processing.

For example:

Say I have the following class tree:

public abstract class AbstractParent {  public String sayHi() {    return getClass().getName() +" instance says hi!";  }}

with subclasses:

public class ChildOne extends AbstractParent {  public int childOneSpecialMethod() {    return 2558445;  }}
public class ChildTwo extends AbstractParent {  public int childTwoSpecialMethod() {    return 484848;  }}

My library allows for users to annotate a class's static methods with the following annotation:

@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface ProcessAnnotation {}

with the following rules: the static method first parameter be an instance of AbstractParent, and its second parameter must be a String, and must return a String. So, something like this:

public class GeneralProcessor {  @ProcessAnnotation  public static String easyProcessing(ChildOne one, String otherArg) {    //Some code    System.out.println(" === In processing for ChildOne types");    return otherArg + one.toString();  }  @ProcessAnnotation  public static String easyProcessing(ChildTwo two, String otherArg) {    //Some code    System.out.println(" === In processing for ChildTwo types");    return otherArg + two.toString();  }}

On the library-side of things, I want to collect all these methods so that I can use them for some processing while doing it in a relatively fast manner and I found that MethodHandles and LambdaMetaFactory is the best way to do this.

Specifically, I want to invoke these collected methods using my own FunctionalInterface :

@FunctionalInterfacepublic interface ProcessInterface<T extends AbstractParent> {  public String process(T obj, String extraArg);}

So far, what I've tried is something like this:

public static List<ProcessInterface<? extends AbstractParent>> generate(Class<?> targetClass) throws Throwable {    ArrayList<ProcessInterface<? extends AbstractParent>> processors = new ArrayList<>();    for (Method method : targetClass.getDeclaredMethods()) {      if (method.isAnnotationPresent(ProcessAnnotation.class) &&          method.getParameterCount() == 2 &&           AbstractParent.class.isAssignableFrom(method.getParameterTypes()[0]) &&          method.getParameterTypes()[1] == String.class) {        MethodHandles.Lookup lookup = MethodHandles.lookup();        MethodHandle handle = lookup.unreflect(method);        CallSite callSite = LambdaMetafactory.metafactory(lookup, "process",                                                           MethodType.methodType(ProcessInterface.class),                                                           MethodType.methodType(String.class,                                                                                 method.getParameterTypes()[0],                                                                                String.class),                                                           handle,                                                           handle.type());        ProcessInterface<? extends AbstractParent> func = (ProcessInterface<? extends AbstractParent>) callSite.getTarget().invoke();        processors.add(func);      }    }    return processors;  }

However, I get the following error when I actually invoke the lambda. For example:

List<ProcessInterface<? extends AbstractParent>> interfaces = generate(GeneralProcessor.class);ChildOne childOne = new ChildOne();interfaces.get(0).process(childOne, "");

Is there a fix to do this? Or maybe even a better way to achieve this?


Viewing all articles
Browse latest Browse all 36

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>