2011-05-16 15 views
15

Sto lavorando ad alcune invocazioni dinamiche del codice tramite un interprete e sto entrando nelle brutte aree di risoluzione dei metodi come discusso in JLS section 15.12.Java: risoluzione del metodo di runtime

Il metodo "facile" per scegliere un metodo è quando si conoscono i tipi esatti di tutti gli argomenti, a quel punto è possibile utilizzare Class.getDeclaredMethod(String name, Class[] parameterTypes). Forse devi controllare l'accessibilità del metodo e le superclassi/superinterfacce della classe.

Ma questo non copre qualsiasi dei seguenti casi, quindi è una specie di inutile:

  • boxe/primitive unboxing
  • sottotipi
  • varargs
  • un argomento null (che può essere qualsiasi tipo, a meno che l'interprete non sappia diversamente, in fase di compilazione qualsiasi ambiguità verrebbe eliminata rilasciando null a una classe/interfaccia)
  • conversione di tipo primitivo (non parte di Java, ma consentita nel contesto delle lingue - ad es. Rinoceronte JavaScript dove tutti i numeri sono virgola mobile, in modo che il codice Java potrebbe richiedere un int ma il chiamante passa in un numero che è o un int o double)

(vedi sotto per un breve esempio del primo tre)

così ora devo scrivere la mia libreria risoluzione metodo ...

c'è qualche libreria quadro ben noto per aiutare in questo?

package com.example.test.reflect; 

import java.lang.reflect.Method; 

public class MethodResolutionTest { 
    public void compute(int i)    { /* implementation... */ } 
    public void compute(Long l)    { /* implementation... */ } 
    public void compute(Object obj)   { /* implementation... */ } 
    public void compute(String... strings) { /* implementation... */ } 

    public static void main(String[] args) { 
     Class<?> cl = MethodResolutionTest.class; 

     /* these succeed */ 
     findAndPrintMethod(cl, "compute", int.class); 
     findAndPrintMethod(cl, "compute", Long.class); 
     findAndPrintMethod(cl, "compute", Object.class); 
     findAndPrintMethod(cl, "compute", String[].class); 

     /* these fail */ 
     findAndPrintMethod(cl, "compute", Integer.class); 
     findAndPrintMethod(cl, "compute", long.class); 
     findAndPrintMethod(cl, "compute", MethodResolutionTest.class); 
     findAndPrintMethod(cl, "compute", String.class, String.class); 
    } 
    private static void findAndPrintMethod(Class<?> objectClass, 
      String methodName, Class<?>... parameterTypes) 
    { 
     try { 
      Method method = findMethod(objectClass, methodName, 
        parameterTypes); 
      System.out.println(method.toString()); 
     } 
     catch (SecurityException e) { 
      e.printStackTrace(); 
     } 
     catch (NoSuchMethodException e) { 
      e.printStackTrace(); 
     } 
    } 
    private static Method findMethod(Class<?> objectClass, 
      String methodName, Class<?>[] parameterTypes) 
     throws SecurityException, NoSuchMethodException 
    { 
     return objectClass.getDeclaredMethod(methodName, parameterTypes); 
    } 
} 
+1

[Questa risposta gestisce alcuni casi come sottotipi] (http://stackoverflow.com/questions/2580665/java-getmethod-with-superclass-parameters-in-method/2580699#2580699). –

+1

@ Jonathon: So di isAssignableFrom. Ho qualcosa di homegrown che funziona con sottotipi e boxe/unboxing. Poi ho iniziato a varargare e mi sono fatto male, e ho pensato, "Aspetta un attimo, perché sto facendo questo?" quindi sono specificamente alla ricerca di una libreria preesistente. (O almeno una buona serie di casi di test preesistenti) Altrimenti posso farlo da solo, ma è un grande dolore. –

+1

A meno che non trovi una dolce biblioteca, penso che qualsiasi cosa tu faccia sarà brutta e difficile da leggere. –

risposta

-1

che ho avuto un certo successo con MVEL e le proprietà, ma non riesco a ricordare se si può inviare chiamate di metodo.

Tuttavia, si potrebbe essere in cerca di una lingua diversa interamente. Data la natura del problema, suggerisco di dare un'occhiata a Groovy, che si integra molto bene con Java.

+0

hmm, sono "bloccato" con Java per vari motivi, il più grande è la manutenibilità (l'aggiunta di un linguaggio diverso limita significativamente la mia capacità di ottenere aiuto da altri sviluppatori) –

2

Commons beanutils hanno questa funzione per la ricerca di metodi corrispondenti: getMatchingAccessibleMethod

Funziona con i tipi primitivi, ma è un po 'come il indeterministica docs dice.

+1

Nota che in 'getMatchingAccessibleMethod' la corrispondenza primitiva è unidirezionale - parametro 'Long.class' corrisponde a' foo (long) 'ma' Long.TYPE' non corrisponde a 'foo (Long)' – McDowell

+0

+1: @Bengt: che sollievo scoprire che Apache ha alcuni strumenti, forse no quello che volevo, ma qualcosa almeno. –

3

Si consiglia di leggere this blog post e di verificare ClassMate. Dovrebbe fare la maggior parte del lavoro sgangherato per te.

+0

ARGH! Così promettente, ma è leggermente diverso: risolve tipi generici, ma non fa nulla per la risoluzione dei metodi. Ma almeno è un inizio, e scommetto che potrei convincere gli autori ad estenderlo. –

0

Uno degli utenti su guava-discuss raccomanda che guardo il Mirror library.

Sfortunatamente non gestisce la risoluzione di sovraccarico, almeno non al momento.

Problemi correlati