Tuesday, April 4, 2017

Java Reflection- Accessing/Modifying private methods/fields

In this post we would access and modify private methods and fields from a class using Java Reflection. This operation wont be possible normally with Java.

Language Used:
Java

Focus Area:
  1. Access a method from a class having private constructor.
  2. Access a private method
  3. Access/Modify a private variable
Git Repo:
https://github.com/csanuragjain/extra/tree/master/ReflectionAccessModifyPrivateData

Related:
https://cooltrickshome.blogspot.in/2017/02/java-reflection-reading-unknown-class.html

Program:

Unknown2.java:
 package com.cooltrickshome;  
 public class Unknown2 {  
      private final String msg="This is final string from private variable";  
      private Unknown2(){  
      }  
      private String privateWelcome(String message)  
      {  
           message=message+" processed by private method";  
           return message;  
      }  
      public void showMessage(){  
           System.out.println("I should not be called since this class constructor is private");  
      }  
 }  

Explanation:
  1. This class has a private variable which is also final. So any other class should not ideally be able to access or modify it.
  2. The constructor of this class is private so you should not be able to create an instance of this class. Because of this we should not be able to call showMessage function.
  3. Method privateWelcome is private so another class should not be able to call this method.

AccessPrivateData.java
 package com.cooltrickshome;  
 import java.lang.reflect.Constructor;  
 import java.lang.reflect.Field;  
 import java.lang.reflect.Method;  
 public class AccessPrivateData {  
      public static void main(String[] args) throws Exception {  
           Class c=Class.forName("com.cooltrickshome.Unknown2");  
           //Class<Unknown2> c=Unknown2.class;  
           Constructor<Unknown2> constr=c.getDeclaredConstructor();  
           constr.setAccessible(true);  
           Unknown2 s=(Unknown2)constr.newInstance();   
           System.out.println("Calling method from class with private constructor:");  
           s.showMessage();   
           System.out.println();  
           Field field = c.getDeclaredField("msg");  
           field.setAccessible(true);  
           System.out.println("Calling private field:");  
           System.out.println(field.get(s));  
           System.out.println();  
           System.out.println("Changing a final variable value:");  
           field.set(s, "I have change a private final variable");  
           System.out.println(field.get(s));  
           System.out.println();  
           Method m= c.getDeclaredMethod("privateWelcome", String.class);  
           m.setAccessible(true);  
           Object o=m.invoke(s, "Calling private method");  
           System.out.println("Calling private method:");  
           System.out.println(o);  
      }  
 }  

Explanation:
  1. We will bypass all the constraint and access all the private data from Unknown2 class
  2. First we reference our Unknown2 class by using Class.forName passing the class to be accessed along with package name.
  3. Now we obtain the constructor of Unknown2 class by callling the getDeclaredConstructor method
  4. Since this contructor is private, so we remove the constraint by setting setAccessible as true
  5. Now we can create a new instance using newInstance method.
  6. Since an instance is ready so we can simply call the showMessage method
  7. Now lets access the private variable
  8. We obtain the private variable of Unknown2 class by calling getDeclaredField passing the field name.
  9. We call setAccessible to true on this field so that we can access this field even though it is private.
  10. Now we can retrieve this field value by simply calling get method passing the class instance object.
  11. Now lets change the final field value.
  12. Since this field setAccessible is already set to true earlier, we simply call the set method passing the Unknown2 class object and the new field value.
  13. Now lets access the private method.
  14. We obtain the private method by calling the getDeclaredMethod passing the private method name nd the type of argument it accepts (in our case the method needs a String)
  15. We call setAccessible to true on this method so that we can access this method even though it is private.
  16. We call the method by using invoke method, passing an instance of this class and the argument value.


Output:
 Calling method from class with private constructor:  
 I should not be called since this class constructor is private  
 Calling private field:  
 This is final string from private variable  
 Changing a final variable value:  
 I have change a private final variable  
 Calling private method:  
 Calling private method processed by private method  


Hope it helps :)