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
:
@FunctionalInterface
public 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?
Aucun commentaire:
Enregistrer un commentaire