Sunday, July 22, 2012

Some use of java.lang.reflect

You should remember it... a private member of a private class or a private method of a library... it's surely inaccessible at compile-time... but it's not completely inaccessible at run-time :)...


This is not the only purpose of java.lang.reflect but it's good to know how to use the main classes of this namespace.


Suppose we have two classes in our project: com.test.Main and com.test.private.TestPrivate.
In Main class there's only the entry-point method static void main(String[] args).
TestPrivate class is without attributes so it's visible only for its namespace.


If I try to create a TestPrivate object on main method, the compiler shows me an error!

package com.test;

public class Main {

 public static void main(String []args)
 {            
          TestPrivate obj= new TestPrivate(); //cannot do this
 }
}

This is the TestPrivate class:
package com.test.pvt;
class TestPrivate {

 private TestPrivate()
 {

  System.out.println("constructor was called"); 
 }
 private void printSomething()
 {
  System.out.println("printSomething was called");
 }
}

So How can I call the method printSomething?
public class Main {

 public static void main(String []args)
 {
  //TestPrivate testPrivate= new TestPrivate() //doesn't work
  Object testPrivate; //TestPrivate is certanily an object so I declare an object
  
  //TestPrivate is private so I access the class in this way
  Class<?> _cl= Class.forName("com.test.pvt.TestPrivate"); //get a class type
  
  //Class is private, contrusctor is private, I need one to instantiate my object
  Constructor<?> constructor= _cl.getDeclaredConstructor(); //get the simplest constructor
  constructor.setAccessible(true); //I must set it as accessible otherwise I get an IllegalAccessException
  
  testPrivate= constructor.newInstance(); //finally I can create my instance!
  
  Method method= _cl.getDeclaredMethod("printSomething"); //now I can choose my method to invoke
  method.setAccessible(true); //set it as accessible because it's private
 
  method.invoke(testPrivate); //and finally invoke the instance method on my object testPrivate
 }
 
}

This is my output
constructor was called
printSomething was called


Let's quickly see another example..
I added to TestPrivateClass a member , another constructor and a non-void method.
package com.test.pvt;
class TestPrivate {

 Integer number;
 
 private TestPrivate()
 {
  System.out.println("constructor was called"); 
 }
 
 TestPrivate(Integer cacheNumber)
 {
  this.number=cacheNumber;
 }
 
 private void printSomething()
 {
  System.out.println("printSomething was called");
 }
 
 private Integer getNextNumber(Integer previousNumber)
 {
  if(number!=null)
   return previousNumber+number+1;
  return previousNumber+1;
 }
} 
I appended to main method of Main class these lines...
Object anotherObject;

Constructor<?> anotherConstructor= _cl.getDeclaredConstructor(Integer.class); 
anotherConstructor.setAccessible(true); 
anotherObject= anotherConstructor.newInstance(1);

Method anotherMethod= _cl.getDeclaredMethod("getNextNumber", Integer.class);
anotherMethod.setAccessible(true);

Object result1=anotherMethod.invoke(testPrivate, 1);
System.out.println("result from testPrivate object = " + result1.toString());

Object result2=anotherMethod.invoke(anotherObject, 1);
System.out.println("result from anotherObject object = " + result2.toString());

Guess the output =)

result from testPrivate object = 2
result from anotherObject object = 3

Imagine the power that you get with reflections.

Enjoy it but be careful... Exceptions are behind the corner :)

These examples just throws the following exceptions: SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException, ClassNotFoundException.

No comments:

Post a Comment