Tutorial :Any way to Invoke a private method?



Question:

I have a class that uses XML and reflection to return Objects to another class.

Normally these objects are sub fields of an external object, but occasionally it's something I want to generate on the fly. I've tried something like this but to no avail. I believe that's because Java won't allow you to access private methods for reflection.

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

If the method provided is private, it fails with a NoSuchMethodException. I could solve it by making the method public, or making another class to derive it from.

Long story short, I was just wondering if there was a way to access a private method via reflection.


Solution:1

You can invoke private method with reflection. Modifying the last bit of the posted code:

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

There are a couple of caveats. First, getDeclaredMethod will only find method declared in the current Class, not inherited from supertypes. So, traverse up the concrete class hierarchy if necessary. Second, a SecurityManager can prevent use of the setAccessible method. So, it may need to run as a PrivilegedAction (using AccessController or Subject).


Solution:2

Use getDeclaredMethod() to get a private Method object and then use method.setAccessible() to allow to actually call it.


Solution:3

If the method accepts non-primitive data type then the following method can be used to invoke a private method of any class:

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

The Parameter accepted are obj, methodName, the count of parameters accepted and the parameters. For example

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

Method concatString can be invoked as

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


Solution:4

Let me provide complete code for execution protected methods via reflection. It supports any types of params including generics, autoboxed params and null values

@SuppressWarnings("unchecked")  public static <T> T executeSuperMethod(Object instance, String methodName, Object... params) throws Exception {      return executeMethod(instance.getClass().getSuperclass(), instance, methodName, params);  }    public static <T> T executeMethod(Object instance, String methodName, Object... params) throws Exception {      return executeMethod(instance.getClass(), instance, methodName, params);  }    @SuppressWarnings("unchecked")  public static <T> T executeMethod(Class clazz, Object instance, String methodName, Object... params) throws Exception {        Method[] allMethods = clazz.getDeclaredMethods();        if (allMethods != null && allMethods.length > 0) {            Class[] paramClasses = Arrays.stream(params).map(p -> p != null ? p.getClass() : null).toArray(Class[]::new);            for (Method method : allMethods) {              String currentMethodName = method.getName();              if (!currentMethodName.equals(methodName)) {                  continue;              }              Type[] pTypes = method.getParameterTypes();              if (pTypes.length == paramClasses.length) {                  boolean goodMethod = true;                  int i = 0;                  for (Type pType : pTypes) {                      if (!ClassUtils.isAssignable(paramClasses[i++], (Class<?>) pType)) {                          goodMethod = false;                          break;                      }                  }                  if (goodMethod) {                      method.setAccessible(true);                      return (T) method.invoke(instance, params);                  }              }          }            throw new MethodNotFoundException("There are no methods found with name " + methodName + " and params " +              Arrays.toString(paramClasses));      }        throw new MethodNotFoundException("There are no methods found with name " + methodName);  }  

Method uses apache ClassUtils for checking compatibility of autoboxed params


Solution:5

One more variant is using very powerfull JOOR library https://github.com/jOOQ/jOOR

MyObject myObject = new MyObject()  on(myObject).get("privateField");    

It allows to modify any fields like final static constants and call yne protected methods without specifying concrete class in the inheritance hierarhy

<!-- https://mvnrepository.com/artifact/org.jooq/joor-java-8 -->  <dependency>       <groupId>org.jooq</groupId>       <artifactId>joor-java-8</artifactId>       <version>0.9.7</version>  </dependency>  


Solution:6

you can do this using ReflectionTestUtils of Sring (org.springframework.test.util.ReflectionTestUtils)

ReflectionTestUtils.invokeMethod(instantiatedObject,"methodName",argument);  

Example : if you have a class with a private method "square(int x)"

Calculator calculator = new Calculator();  ReflectionTestUtils.invokeMethod(calculator,"square",10);  

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »