2016-09-29 3 views
1

ich eine Liste von Methoden erhalten kann, die kein Problem mit Anmerkungen versehen werden ...Java-Reflektion eine Methode als Parameter einer anderen Methode übergeben?

Method[] m = clazz.getDeclaredMethods(); 

Nun möchte Ich mag die Methode zu übergeben [x] zu einer Funktion. Zum Beispiel ...

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

Ich möchte es an den Handler als eine Methodenreferenz übergeben.

In 8 Java können wir tun, nur router.get("/").handler(this::myMethod)

Aktualisiert Beispiel:

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(); 
} 

Ich möchte die Funktion myHandler mit Anmerkungen zu versehen, damit ich es reflektiv finden und fügen Sie es dem „Router“ . So mit Reflexion kann ich eine Liste von Methoden erhalten, die kein Problem und dann für jeden fügen Sie es zu meinem Router mit Anmerkungen versehen sind ...

Also sage ich einige „web“ anotations haben ...

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

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

Ich kann diese Methoden mit Reflektion auflisten. Cool kein Problem. Aber dann möchte ich sie als Methodenreferenzen an router.handler() übergeben, wie im obigen Beispiel gezeigt ...

Wenn Sie es nicht für ein Web-Framework erraten haben und nein, ich werde es nicht auf die wild, nicht wie wir einen anderen brauchen. Es ist für Lernzwecke lol.

aktualisieren

Router vom Typ: https://github.com/vert-x3/vertx-web/blob/master/vertx-web/src/main/java/io/vertx/ext/web/Router.java und

Und Hander Teil ist vertx.io

+0

Suchen Sie, wie in der Reflexion die spezifische Methode mit Namen zu bekommen? – mhasan

+0

Nein, das weiß ich. Aber ich möchte die Methodenreferenz/Lambda an eine andere Funktion übergeben ... – user432024

+1

Ihre Frage kann tatsächlich ein [XY-Problem] (http://mywiki.wooledge.org/XyProblem) sein, wo Sie fragen "Wie behebe ich das? Code-Problem ", wenn die beste Lösung ist, einen ganz anderen Ansatz zu verwenden. Denken Sie daran, uns das Gesamtproblem zu nennen, das Sie lösen möchten, und nicht, wie Sie es gerade lösen wollen. –

Antwort

2

Sie können einfach einen Lambda-Ausdruck übergeben, der den reflektiven Aufruf durchführt, z.

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

was macht den Job.

Alternativ können Sie tatsächlich eine Instanz generieren, die einer Methodenreferenz entspricht. Dies erfordert tiefere Kenntnisse über reflektive Operationen (und die Handler Schnittstelle, die Sie nicht veröffentlicht haben). Z.B. zu generieren Ihr ein Consumer<RoutingContext> Aufruf method Sie verwenden können:

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); 

Um ein Handler stattdessen zu generieren, Sie haben das Auftreten von Consumer mit Handler und "accept" mit dem Namen des Funktionsmethode Handler zu ersetzen. Wenn der Typparameter Handler eine andere untere Schranke als Object hat, müssen Sie Object.class durch den unformatierten Typ der unteren Schranke ersetzen.

Die documentation of LambdaMetaFactory ist sehr erschöpfend, und es gibt related Q&A’s on SO mehr Informationen, aber wenn Sie irgendwelche Zweifel haben, bleiben nur auf die reflektierende Aufruf ...

+0

Ok, probieren Sie es aus. Aber wenn ot hilft ... Router ist von https: // github.com/vert-x3/vertex-web/blob/master/vertex-web/src/main/java/io/vertex/ext/web/Router.java und handler ist auch ein teil von vertex ... – user432024

+1

So 'Handler' unterscheidet sich von "Consumer" nur im Methodennamen, dh Sie müssen "accept" durch "handle" ersetzen ... – Holger

+0

Beide Lösungen funktionieren :) – user432024

0

Wenn Sie eine Methode Referenz verwenden, die Art der Referenz ist eine Klasse, implementiert einen Schnittstellentyp (speziell eine Funktionsschnittstelle). In Ihrem Fall sieht der Typ Ihrer Methodenreferenz wie folgt aus: Handler<RoutingContext>.

Sie scheinen nach einer Möglichkeit zu suchen, eine Method zu einer funktionalen Schnittstelle Ihrer Wahl zu konvertieren. Ich weiß nicht, von einer direkten Art und Weise, das zu tun, aber man könnte so etwas wie

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); 
    } 
} 

Nun versuchen, wenn Sie ein Method m haben, schafft new HandlerFromMethod(m) ein Objekt, das als Handler<RoutingMethod> verwendet werden kann, und rufe m wenn angerufen.

Wenn es sich bei der Methode um eine Instanzmethode handelt, müssen Sie dem Konstruktor einen weiteren Parameter hinzufügen, um die zu bearbeitende Instanz anzugeben, und diesen als ersten Parameter für invoke verwenden.

Ich gehe davon aus, dass die Methode in Handler heißt apply; Wenn es sich um etwas anderes handelt, ändern Sie den Namen im obigen Code.

Haftungsausschluss: Ich habe dies nicht getestet.

+1

Da wir davon ausgehen, dass "Handler" eine funktionale Schnittstelle ist, gibt es keine Notwendigkeit, auf eine gewöhnliche Klasse zurückzugreifen statt einen Lambda-Ausdruck zu verwenden. Der einzige Grund, es nicht zu verwenden, wäre die größere Größe aufgrund der erforderlichen Ausnahmebehandlung, aber Sie haben diesen Teil in Ihrem Code trotzdem weggelassen. Aus dem Kontext des OPs wird klar, dass die Zielmethoden Instanzmethoden sind, so dass die Übergabe von "null" als Zielinstanz nicht funktioniert. – Holger

+0

Richtig, aber die Verwendung einer separaten Klasse kann die Dinge lesbarer machen, insbesondere wenn sie mehrmals verwendet wird. YMMV. – ajb

Verwandte Themen