2012-03-25 12 views
11

Estoy buscando una solución conveniente para obtener el objeto Método de un método. La idea:Cómo obtener el objeto Método en Java sin usar los nombres de cadena de método

Method fooMethod = getMethod(new MyObject().foo()) // returns method "foo" in MyObject 

La manera obvia es utilizar el nombre del método como una cadena:

Method fooMethod = MyObject.class.getMethod("foo") 

pero quiero evitar esto porque si cambio el nombre foo() que el código dejará de funcionar o he cambiado el nombre de la cadena en todos los lugares donde se usa.

El caso de uso es que quiero usar algo similar a ProperyChangeListeners, pero estos se basan en el nombre del método como cadena. Me gustaría usar el método real (de forma segura) y no depender de cadenas.

¿Qué podría usar para obtener el método en un cambiar el nombre seguro manera?

ACTUALIZACIÓN: Me gustaría encontrar una solución pura de Java que no se basa en el IDE cuenta con

+1

Aunque, como otros mencionan los IDE, pueden quitarle parte del dolor, lo que usted describe actualmente no es posible. Me parece recordar una petición de características/JSR proponiendo una sintaxis como 'MyObject # foo' o algo así, pero ya no puedo encontrarlo. –

+0

Aunque no es posible, estoy buscando posibles soluciones alternativas que actualmente se pueden usar – Andrejs

+2

@ArnoutEngelen Las lambdas de Java 8 están programadas para tener una funcionalidad similar: http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state -4.html (sección 8). Tenga en cuenta que esto no le dará un Método, sino una lambda que luego puede invocar. – yshavit

Respuesta

6

En realidad, hay una biblioteca que puede hacer esto:

Jodd MethRef - nombre del método inflexible de tipos hace referencia a

http://jodd.org/doc/methref.html

Methref<Str> m = Methref.on(Str.class); // create Methref tool 

// example #1 
m.to().boo(); 
m.ref();        // returns String: 'boo' 
+0

Muy bien, pero sería un poco más frío si devuelven el 'Método' en lugar de solo su nombre. – shmosel

2

Lo más seguro es usar un IDE con capacidad de refactorización que es lo suficientemente inteligente como para reconocer y reemplazar esa cadena nombre del método. IntelliJ de JetBrains lo hace, solo lo probé para mí.

+0

De manera predeterminada, Eclipse no hace lo mismo para los métodos, solo las clases. Podría usar la búsqueda, pero no siempre sabré que necesito buscar referencias de cadenas. – Andrejs

+1

Como dije, IntelliJ sabe cómo hacerlo. Te recomendaría que obtengas un IDE superior. Eclipse no es eso. – duffymo

+0

IntellJ desafortunadamente también solo puede usar heurística. Por ejemplo, puede suceder que un método del mismo nombre pero diferente clase se renombre en una cadena totalmente no relacionada. Esto es especialmente horrible cuando intenta cambiar el nombre de un método 'getId' o' isActive', que puede existir en muchas clases totalmente independientes. – Svante

0

Puede utilizar la refactorización IDE que también se ocupa de todas las ocurrencias de cadenas.

No se puede hacer referencia a un método utilizando la reflexión de otra manera que por su nombre.

0

Al usar la reflexión, se está renunciando a la seguridad en tiempo de compilación, simplemente por su naturaleza.

En lugar de considerar si la reflexión es realmente necesaria aquí. Se podía representar a su método con un Runnable, por ejemplo:

Runnable foo = new Runnable() { 
    @Override 
    public void run() { 
     new MyObject().foo(); 
    } 
} 

... 

foo.run(); 

O si usted necesita para representar un método con un tipo de retorno, mira Callable - o mejor aún, la guayaba de Function.

+0

Sí, podría, pero eso también significaría envolver cada método que necesita ser utilizado. No sería tan conveniente – Andrejs

+0

Me gustaría ver una explicación de lo que te llevó a esta decisión de diseño. Todavía no estoy convencido de que la reflexión sea necesaria para lo que estás haciendo. Este tipo de diseño basado en la búsqueda en tiempo de ejecución será difícil de mantener y depurar en el futuro. –

+0

Se agregó el caso de uso PropertyChangeListener a la pregunta original. – Andrejs

6

En su método llame al: Método me = (new MethodNameHelper() {}). GetMethod();

/** 
* Proper use of this class is 
*  Method me = (new MethodNameHelper(){}).getMethod(); 
* the anonymous class allows easy access to the method name of the enclosing scope. 
*/ 
public class MethodNameHelper { 
    public Method getMethod() { 
    return this.getClass().getEnclosingMethod(); 
    } 
} 
+0

¿Sugiere subclasificar el MyObject original y reemplazar el método foo() para usar este helper? – Andrejs

+0

No es necesario crear una subclase de MyObject. Have foo() llame al ** Método me = (new MethodNameHelper() {}). GetMethod(); ** y guarde o use ese resultado como lo hubiera deseado. No mencionó cómo quería ** utilizar ** el objeto ** Método **. – Jim

+1

Bastante justo. El problema es que foo() ya tendrá algún código que preferiría no cambiar o podría provenir de un tercero.Aún así, ¿cómo devolvería el Método al código de llamada (por ejemplo, principal). – Andrejs

2

Es posible que desee utilizar anotaciones. Puede crear una anotación personalizada para cada método que desee recuperar y el reflejo de atracción extraer ese método del objeto.

Puede cambiar el nombre del método de manera segura y su código funcionará.

Si desea poder recuperar muchos métodos, utilice solo una anotación con un valor de cadena que cambiará por método y luego su código de reflexión buscará aquellas anotaciones con ese valor de cadena. Aún puedes cambiar el nombre de tu método siempre que dejes el valor de cadena de la anotación igual.

6

Las referencias al método Java 8 serían ideales para esto; la parte difícil es llegar al método subyacente, porque la sintaxis de referencia del método en sí misma da como resultado un objeto lambda opaco.

Encontramos este después de un poco de búsqueda:

http://benjiweber.co.uk/blog/2013/12/28/typesafe-database-interaction-with-java-8/

Buen truco - llamar al método de un objeto proxy que registra el nombre del método. No lo he intentado, pero parece prometedor.

+2

Intenta agregar más información en la respuesta en sí, los enlaces pueden quedarse obsoletos :) – achedeuzot

1

Hemos publicado la pequeña biblioteca de.cronn:reflection-util que se puede utilizar capturar un método

Ejemplo:

class MyClass { 

    public void myMethod() { 
    } 

} 

Method method = ClassUtils.getVoidMethod(MyClass.class, MyClass::myMethod); 
System.out.println(method.getName()); // prints "myMethod" 

Detalles de la implementación: Una subclase Proxy de MyClass se crea con ByteBuddy y una llamada al método se captura para recuperar su nombre. ClassUtils almacena en caché la información de manera que no es necesario crear un nuevo proxy en cada invocación.

Cuestiones relacionadas