2009-05-19 19 views
107

Tengo una clase que usa XML y reflejo para devolver Object a otra clase.¿Alguna manera de invocar un método privado?

Normalmente, estos objetos son subcampos de un objeto externo, pero ocasionalmente es algo que quiero generar sobre la marcha. He intentado algo como esto, pero fue en vano. Creo que es porque Java no le permitirá acceder a los métodos private para la reflexión.

Element node = outerNode.item(0); 
String methodName = node.getAttribute("method"); 
String objectName = node.getAttribute("object"); 

if ("SomeObject".equals(objectName)) 
    object = someObject; 
else 
    object = this; 

method = object.getClass().getMethod(methodName, (Class[]) null); 

Si el método es proporcionado private, se produce un error con un NoSuchMethodException. Podría resolverlo haciendo el método public, o haciendo otra clase para derivarlo.

En pocas palabras, solo me preguntaba si había una forma de acceder a un método private a través de la reflexión.

Respuesta

233

Puede invocar el método privado con la reflexión. Modificar el último bit del código publicado:

Method method = object.getClass().getDeclaredMethod(methodName); 
method.setAccessible(true); 
Object r = method.invoke(object); 

Hay un par de advertencias. Primero, getDeclaredMethod solo encontrará el método declarado en el actual Class, no heredado de supertipos. Por lo tanto, recorra la jerarquía de clases concretas si es necesario. En segundo lugar, un SecurityManager puede evitar el uso del método setAccessible. Por lo tanto, es posible que deba ejecutarse como PrivilegedAction (usando AccessController o Subject).

+1

cuando hice esto en el pasado, también llamé a method.setAccessible (falso) después de llamar al método, pero no tengo idea si esto es necesario o no. – shsteimer

+12

No, cuando establece la accesibilidad, solo se aplica a esa instancia. Siempre y cuando no permitas que ese objeto particular del Método escape de tu control, es seguro. – erickson

+5

Estoy intercambiando amor, compañero. Respuesta impresionante + código incorrecto == día no tan malo. – droope

32

Utilice getDeclaredMethod() para obtener un objeto Método privado y luego use method.setAccessible() para permitir realmente llamarlo.

+7

La respuesta aceptada es en realidad completa. –

+0

En mi propio ejemplo (http://stackoverflow.com/a/15612040/257233) obtengo un 'java.lang.StackOverflowError' si no llamo' setAccessible (true) '. –

21

Si el método acepta el tipo de datos no primitivos entonces el siguiente método se puede utilizar para invocar un método privado de cualquier clase:

public static Object genericInvokMethod(Object obj, String methodName, 
      int paramCount, Object... params) { 
     Method method; 
     Object requiredObj = null; 
     Object[] parameters = new Object[paramCount]; 
     Class<?>[] classArray = new Class<?>[paramCount]; 
     for (int i = 0; i < paramCount; i++) { 
      parameters[i] = params[i]; 
      classArray[i] = params[i].getClass(); 
     } 
     try { 
      method = obj.getClass().getDeclaredMethod(methodName, classArray); 
      method.setAccessible(true); 
      requiredObj = method.invoke(obj, params); 
     } catch (NoSuchMethodException e) { 
      e.printStackTrace(); 
     } catch (IllegalArgumentException e) { 
      e.printStackTrace(); 
     } catch (IllegalAccessException e) { 
      e.printStackTrace(); 
     } catch (InvocationTargetException e) { 
      e.printStackTrace(); 
     } 

     return requiredObj; 
    } 

El parámetro aceptado son obj, methodName, el recuento de los parámetros aceptados y Los parametros. Por ejemplo

public class Test { 
private String concatString(String a, String b) { 
    return (a+b); 
} 
} 

concatString método puede ser invocada como

Test t = new Test(); 
    String str = (String) genericInvokMethod(t, "concatString", 2, "Hello", "Mr.x"); 
+5

¿Por qué se necesita _paramCount_? ¿No puedes usar * params.length *? –

Cuestiones relacionadas