Java将字符串变量作为回调函数传递

Java将字符串变量作为回调函数传递,java,java-8,vert.x,Java,Java 8,Vert.x,如何在回调中传递方法类变量 我有以下代码: PostsController postController = new PostsController(); router.get("/").handler(postController::index); 但我的控制器将是动态的,我如何传递动态类及其函数。 我尝试了以下代码 Class controller = Class.forName("some.package"+controllerName); //PostsController Metho

如何在回调中传递方法类变量

我有以下代码:

PostsController postController = new PostsController();
router.get("/").handler(postController::index);
但我的控制器将是动态的,我如何传递动态类及其函数。 我尝试了以下代码

Class controller = Class.forName("some.package"+controllerName); //PostsController
Method[] methods = controller.getMethods();
//some loop
Method m = methods[i]; // This is the index method of my controller
router.get(somePath).handler(m); // How can I pass my method m as callback?
后置控制器

public class PostsController {

    @Route(method="get", path = "/")
    public void index(RoutingContext routingContext){
        routingContext.response()
                .putHeader("content-type", "application/json; charset=utf-8")
                .end(Json.encodePrettily("{}"));
    }

}

我看到的第一件事是,您需要创建类的实例

Class controller = Class.forName("some.package"+controllers.getString(i));
Object myInstance = controller.newInstance();
然后从中获取方法,并调用它:

Method myMethod = ...
myMethod.invoke(myInstance, null);  // or with some params
如果您只需要调用“index”,还可以让控制器实现一个公共接口,然后:

MyInterface myInterface = (MyInterface) myInstance;
myInterface.index();

希望这有帮助

最干净的解决方案是使用定义通用功能的
接口,例如

public interface Controller {
    void index(RoutingContext routingContext);
}
public class PostsController implements Controller {
    @Route(method="get", path = "/")
    public void index(RoutingContext routingContext){
        routingContext.response()
                .putHeader("content-type", "application/json; charset=utf-8")
                .end(Json.encodePrettily("{}"));
    }
}


但这并不能改变这样一个事实,即您只会很晚才检测到错误…

您是否不需要保证您的所有控制器都有此
索引
方法?通过使控制器扩展一些需要index方法的接口来解决这个问题。index函数将是它们的函数,但也会有一些自定义函数,这就是为什么我要使其动态化,只要该文件实现该接口,您的自定义函数都可以在该文件中声明。然而,JVM不知道您可以保证您的文件具有该方法。您可以通过让所有控制器实现一个公共接口来保证这一点。我已经编辑了我的问题,请再次阅读。我尝试了这个
router.get(annotation.path()).handler(((handler)m.invoke(controller.newInstance(),null))
它抛出一个错误,如
java.lang.IllegalArgumentException:参数数目错误
显然,由于您为方法avec编制了一个参数索引,因此需要提供它。但是invoke将实际执行该函数,我希望将其作为回调传递。Handler将为回调函数提供参数,然后您需要您的Handler调用invoke。我不知道您的路由器对象是什么,但调用方法的逻辑必须在
Handler(…)
方法中。如果它是某个框架类,您可能需要创建自己的类。谢谢,我尝试过这样做,但它给我带来了一个错误:
java.lang.AbstractMethodError:io.vertx.lib.AppVertical$$Lambda$28/647430455.handle(Ljava/lang/Object;)V
,如前所述,您必须修改方法名称:
“accept”
→ <代码>“handle”
。谢谢,这很有效:)界面看起来干净且简单,但是如果我在controller中有动态方法,那么更干净的方法是什么呢?对于具有动态发现的框架,一些反射是不可避免的。我也使用类似于
createHandler
方法的代码。将这些东西放在一个孤立的地方,而不是让反射操作在整个应用程序中传播,这一点很重要。如果使用正确,它与编译时方法引用一样平滑。
Class<? extends Controller> controllerType =
    Class.forName("some.package"+controllers.getString(i))
         .asSubclass(Controller.class);
Controller controller=controllerType.newInstance();
Handler<RoutingContext> h=controller::index;
Class<?> controllerType = Class.forName("some.package"+controllers.getString(i));
MethodHandles.Lookup lookup=MethodHandles.lookup();
Method[] methods = controllerType.getMethods();
Object instance = null;
for (Method m : methods) {
    Route annotation = m.getAnnotation(Route.class);
    if (annotation != null) {
        if(instance == null) instance = controllerType.newInstance();
        Handler<RoutingContext> handler
            =createHandler(lookup, instance, m, RoutingContext.class);
        router.get(annotation.path()).handler(handler);
    }
}
static <T> Handler<T> createHandler(MethodHandles.Lookup lookup,
        Object instance, Method m, Class<T> arg) throws Throwable {

    MethodHandle mh=lookup.unreflect(m);
    MethodType t=mh.type();
    Class<?> receiver=t.parameterType(0);
    if(t.parameterCount()!=2
    || !receiver.isAssignableFrom(instance.getClass())
    || !t.parameterType(1).isAssignableFrom(arg))
      throw new IllegalArgumentException(m+" not suitable for Handler<"+arg.getName()+'>');
    t=t.dropParameterTypes(0, 1);
    return (Handler)LambdaMetafactory.metafactory(lookup, "accept",
        MethodType.methodType(Handler.class, receiver),
        t.changeParameterType(0, Object.class), mh, t)
        .getTarget().invoke(instance);
}
Handler<RoutingContext> handler=rc -> { try {
    m.invoke(capturedInstance, rc);
} catch(ReflectiveOperationException ex) { ex.printStackTrace(); }};