1

I can get a list of methods that are annotated no problem...

Method[] m = clazz.getDeclaredMethods();

Now I would like to pass the method[x] to a function. For instance...

router.get("/").handler(RoutingContext handler)

I would like to pass it to the handler as a method reference.

In java 8 we can just do router.get("/").handler(this::myMethod)

Updated example:

public void myFunction() throws Exception {

    Router routes = Router.router(...);

    Handler<RoutingContext> handler = this::myHandler;
    routes.route("/").handler(handler);
    routes.route("/someOtherRoute").handler(this::anotherHandler);

}

public void myHandler(final RoutingContext rcs) {
    rcs.doSomething();
}

I would like to annotate the function myHandler so I can find it reflectively and add it to the "Router". So with reflection I can get a list of methods that have been annotated no problem and then for each one add it to my router...

So say I have some "web" anotations...

@GET
public void myHandler(final RoutingContext rcs) {
    rcs.doSomething();
}

@POST
public void anotherHandler(final RoutingContext rcs) {
    rcs.doSomething();
}

I can list these methods using reflection. Cool no problem. But then I would like to pass them as method references to router.handler() as shown in the above example...

If you haven't guessed it it for a web framework and no I wont release it to the wild not like we need another one. It's for learning purposes lol.

Update

Router is of type: https://github.com/vert-x3/vertx-web/blob/master/vertx-web/src/main/java/io/vertx/ext/web/Router.java and

And hander is part of vertx.io

12
  • Are you looking for how to get the specific method by name in reflection? Commented Sep 29, 2016 at 3:12
  • No, that I know. But I want to pass the method reference/lambda to another function... Commented Sep 29, 2016 at 3:14
  • 1
    Your question may in fact be an XY Problem where you ask "how do I fix this code problem" when the best solution is to use a different approach entirely. Consider telling us the overall problem that you're trying to solve rather than how you're currently trying to solve it. Commented Sep 29, 2016 at 3:17
  • Not sure about that. I'm not sure how to get to it. Basically I would like to to figure which methods are in a class and then pass them to the other function. It's a reflection issue. But I'm not sure how it's done or even possible. Commented Sep 29, 2016 at 3:19
  • 2
    Learn how to invoke a method reflectively. Then pass a lambda that invokes the method reflectively. Commented Sep 29, 2016 at 3:24

2 Answers 2

2

You can simply pass a lambda expression performing the reflective invocation, e.g.

routes.route("/").handler(rc -> { try { method.invoke(this, rc); }
    catch (ReflectiveOperationException ex) { throw new RuntimeException(ex);}
} );

which does the job.

Alternatively, you can indeed generate an instance equivalent to a method reference, which requires deeper knowledge about reflective operations (and the Handler interface which you didn’t post). E.g. to generate a Consumer<RoutingContext> invoking your method you can use:

MethodHandles.Lookup l=MethodHandles.lookup();
Consumer<RoutingContext> c=(Consumer<RoutingContext>)
  LambdaMetafactory.metafactory(l, "accept",
    MethodType.methodType(Consumer.class, getClass()),
    MethodType.methodType(void.class, Object.class), l.unreflect(method),
    MethodType.methodType(void.class, RoutingContext.class))
  .getTarget().invoke(this);

To generate a Handler instead, you have to replace the occurrences of Consumer with Handler and "accept" with the name of the functional method of Handler. Also, if Handler’s type parameter has a lower bound other than Object, you have to replace Object.class with the raw type of the lower bound.

The documentation of LambdaMetaFactory is very exhaustive and there are related Q&A’s on SO providing more information, however, if you have any doubts, just stick to the reflective invocation…

Sign up to request clarification or add additional context in comments.

2 Comments

Ok ill try it out. But if ot helps... Router is of github.com/vert-x3/vertx-web/blob/master/vertx-web/src/main/… and handler also is part of vertx...
So Handler differs from Consumer only in the method’s name, i.e. you have to replace "accept" with "handle"
0

When you use a method reference, the type of the reference is a class that implements an interface type (specifically, a functional interface). In your case, it looks like the type of your method reference is Handler<RoutingContext>.

You seem to be looking for a way to convert a Method to a functional interface of your choosing. I don't know of a direct way to do that, but you could try something like

public class HandlerFromMethod implements Handler<RoutingContext> {

    final private Method method;

    public HandlerFromMethod(Method m) {
        method = m; 
    }

    @Override
    public void apply(final RoutingContext rcs) {
        method.invoke(null, rcs);
    }
}

Now if you have a Method m, new HandlerFromMethod(m) creates an object that can be used as a Handler<RoutingMethod>, and will invoke m when called.

If the method is an instance method, then you'll want to add another parameter to the constructor to specify the instance it will operate on, and use that as the first parameter to invoke.

I'm assuming that the method in Handler is named apply; if it's something else, then change the name in the above code.

Disclaimer: I haven't tested this.

2 Comments

Since we assume that Handler is a functional interface, there is no need to fall back to an ordinary class instead of using a lambda expression. The only reason, not to use it, would be the bigger size due to the required exception handling, however, you left off that part in your code anyway. Besides, it’s clear from the OP’s context, that the target methods are instance methods, so passing null as target instance won’t work.
Right, but using a separate class may make things more readable, especially if it will be used a number of times. YMMV.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.