Tuesday, March 27, 2007

Java accesibility hack

Invoking a private method/variable using reflection in java is very simple. In the example I invoke the private methodA of the class.

public class A
{
private void methodA()
{
System.out.println("methodA");
}
}
This is pretty simple. But can we achieve this by setting setAccessible(true) for the Method.

public class B
{
public static void main(String[] args) throws Exception
{
A a = new A();
Method method = A.class.getDeclaredMethod("methodA");
method.setAccessible(true);
method.invoke(a,new Object[]{});
}
}


And the result is that methodA is printed on the console.

Now can we achieve this without the use of reflection? Yes we can and thats the java hack. I'll
explain how...

First write the class A, but mark the methodA as public. Then create a class B as

public class B
{
public static void main(String[] args) throws Exception
{
A a = new A();
a.methodA();
}
}

Compile class A and class B.
javac A
javac B

Run class B.
java B

The output is methodA as expected.

But where is the hack?
Now it comes..

Change the class A and change methodA as private again. Compile class A again only.
javac A

Do not try to compile class B, it will result in an comilation error. Now run B
java B

The output is not an Runtime error, but is methodA.

You can decompile using any java decompiler and see that methodA is still private but still B can invoke it. The probable reason for this is that accessiblity is a compile time check not a runtime one. At runtime it cannot be determined whether it is invoked using this hack or reflection. I cannot think of any other reason this is not done.

No comments: