Source:
public ClientResponseHandler generateHandlers(@NonNull final MethodHandles.Lookup caller, @NonNull final Object o) { Arrays.stream(o.getClass().getDeclaredMethods()) .filter(method -> method.isAnnotationPresent(ResponseHandler.class)) .forEach(method -> { ResponseHandler handler = method.getAnnotation(ResponseHandler.class); if (!method.getParameterTypes()[0] .isAssignableFrom(ResponseMsg.class)) { throw new RuntimeException("Incorrect message type, expected " + ResponseMsg.class + " but provided " + method.getParameterTypes()[0]); } if (handlerMap.containsKey(handler.type())) { throw new RuntimeException("Handler for " + handler.type() + " already registered!"); } try { if (Modifier.isStatic(method.getModifiers())) { MethodHandle mh = caller.unreflect(method); MethodType mt = mh.type().changeParameterType(0, ResponseMsg.class); handlerMap.put(handler.type(), (Handler) LambdaMetafactory .metafactory(caller, "handle", MethodType.methodType(Handler.class), mt, mh, mh.type()) .getTarget().invokeExact()); } else { MethodType mt = MethodType .methodType(method.getReturnType(), method.getParameterTypes()); MethodHandle mh = caller.findVirtual(o.getClass(), method.getName(), mt); MethodType mtGeneric = mh.type() .changeParameterType(1, ResponseMsg.class) .changeReturnType(Object.class); handlerMap.put(handler.type(), (Handler) LambdaMetafactory .metafactory(caller, "handle", MethodType.methodType(Handler.class, o.getClass()), mtGeneric.dropParameterTypes(0, 1), mh, mh.type() .dropParameterTypes(0, 1)) .getTarget().bindTo(o).invoke()); } } catch (Throwable e) { log.error("Exception during incoming message handling", e); throw new RuntimeException(e); } }); return this; }

Target:
public ClientResponseHandler generateHandlers(@NonNull final MethodHandles.Lookup caller, @NonNull final Object o) { Arrays.stream(o.getClass().getDeclaredMethods()) .filter(method -> method.isAnnotationPresent(ResponseHandler.class)) .forEach(method -> { ResponseHandler handler = method.getAnnotation(ResponseHandler.class); if (!method.getParameterTypes()[0] .isAssignableFrom(ResponseMsg.class)) { throw new RuntimeException("Incorrect message type, expected " + ResponseMsg.class + " but provided " + method.getParameterTypes()[0]); } if (handlerMap.containsKey(handler.type())) { throw new RuntimeException("Handler for " + handler.type() + " already registered!"); } try { if (Modifier.isStatic(method.getModifiers())) { MethodHandle mh = caller.unreflect(method); handlerMap.put(handler.type(), (Handler) LambdaMetafactory .metafactory(caller, "handle", MethodType.methodType(Handler.class), mh.type(), mh, mh.type()) .getTarget().invokeExact()); } else { MethodType mt = MethodType .methodType(method.getReturnType(), method.getParameterTypes()); MethodHandle mh = caller.findVirtual(o.getClass(), method.getName(), mt); MethodType mtGeneric = mh.type() .changeReturnType(Object.class); handlerMap.put(handler.type(), (Handler) LambdaMetafactory .metafactory(caller, "handle", MethodType.methodType(Handler.class, o.getClass()), mtGeneric.dropParameterTypes(0, 1), mh, mh.type() .dropParameterTypes(0, 1)) .getTarget().bindTo(o).invoke()); } } catch (Throwable e) { log.error("Exception during incoming message handling", e); throw new RuntimeException(e); } }); return this; }