Despite having read all the documentation I'm aware of, I cannot resolve an issue with using lambdas to execute a method. To give a bit of background my use case is a plugin system. I'm using an annotation (@EventHandle) which can be assigned to any method. I use reflection and iterate through every method in the class and check if it has the annotation, if it does the method is added to a handler object (which is added to a list for processing every "tick"). Here is my handler class:
package me.b3nw.dev.Events;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import java.lang.invoke.*;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
@Slf4j
public class Handler {
@Getter
private final Method method;
@Getter
private final EventHandle handle;
private final MethodHandles.Lookup lookup;
private final MethodHandle methodHandle;
private final EventHandler invoker;
public Handler(Method method, EventHandle handle) throws Throwable {
this.method = method;
log.info(method.getGenericReturnType() + "");
for(Type type : method.getParameterTypes()) {
log.info(type.getTypeName());
}
this.handle = handle;
this.lookup = MethodHandles.lookup();
this.methodHandle = lookup.unreflect(method);
log.info("" + methodHandle.type().toMethodDescriptorString());
this.invoker = (EventHandler) LambdaMetafactory.metafactory(lookup, "handle", MethodType.methodType(EventHandler.class), methodHandle.type(), methodHandle, methodHandle.type()).getTarget().invokeExact();
}
public void invoke(GameEvent evt) throws Throwable {
invoker.handle(evt);
}
}
In the current iteration of this class I'm casting straight to the functional interface EventHandler, source:
package me.b3nw.dev.Events;
@FunctionalInterface
public interface EventHandler {
boolean handle(GameEvent evt);
}
Currently I get the following error:
ERROR m.b.d.H.GamemodeHandler -
java.lang.AbstractMethodError: me.b3nw.dev.Events.Handler$$Lambda$3/1704984363.handle(Lme/b3nw/dev/Events/GameEvent;)Z
at me.b3nw.dev.Events.Handler.invoke(Handler.java:40) ~[classes/:na]
at me.b3nw.dev.Handlers.GamemodeHandler.userEventTriggered(GamemodeHandler.java:34) ~[classes/:na]
GamemodeHandler just calls the invoke method in Handler class.
So it outputs an AbstractMethodError when I cast straight to EventHandler and execute, when I don't cast it I get a different error which is:
java.lang.invoke.WrongMethodTypeException: expected ()EventHandler but found ()void
at java.lang.invoke.Invokers.newWrongMethodTypeException(Invokers.java:294) ~[na:1.8.0_45]
at java.lang.invoke.Invokers.checkExactType(Invokers.java:305) ~[na:1.8.0_45]
at me.b3nw.dev.Events.Handler.invoke(Handler.java:40) ~[classes/:na]
at me.b3nw.dev.Handlers.GamemodeHandler.userEventTriggered(GamemodeHandler.java:34) ~[classes/:na]
The modified Handler to reflect changes:
package me.b3nw.dev.Events;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import java.lang.invoke.*;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
@Slf4j
public class Handler {
@Getter
private final Method method;
@Getter
private final EventHandle handle;
private final MethodHandles.Lookup lookup;
private final MethodHandle methodHandle;
private final MethodHandle invoker;
public Handler(Method method, EventHandle handle) throws Throwable {
this.method = method;
log.info(method.getGenericReturnType() + "");
for(Type type : method.getParameterTypes()) {
log.info(type.getTypeName());
}
this.handle = handle;
this.lookup = MethodHandles.lookup();
this.methodHandle = lookup.unreflect(method);
log.info("" + methodHandle.type().toMethodDescriptorString());
this.invoker = LambdaMetafactory.metafactory(lookup, "handle", MethodType.methodType(EventHandler.class), methodHandle.type(), methodHandle, methodHandle.type()).getTarget();
}
public void invoke(GameEvent evt) throws Throwable {
invoker.invokeExact();
}
}
This class has a method which is annotated and should implement the signature of the functional interface but.. clearly not :( Here's the class:
package me.b3nw.dev.Gamemode;
import lombok.extern.slf4j.Slf4j;
import me.b3nw.dev.Events.EventHandle;
import me.b3nw.dev.Events.GameEvent;
@Slf4j
public class Vanilla extends Gamemode {
public void testMethod() {
}
@EventHandle(type = EventHandle.Type.NICKANNOUNCE)
public boolean testMethod2(GameEvent evt) {
log.info("Fuck yeah!"/* + evt*/);
return true;
}
}
How do I go about fixing this, am I using lambdas completely wrong here?
Thank you.