Friday, February 23, 2007

private members, are they private?

Today I was to this Seam presentation by David Geary, and it was the first time I was actually seeing an EJB 3 code in which I pointed out Seam is magically (k, I mean using reflection) setting private members of a bean class. This was the first time I had to think if that is actually possible. Guess what? Yes it is possible.

Consider this example:

package test;

public class TestClass {

      private int a = 2;

      public void printA()
      {
            System.out.println(">> a =" + a);
      }
}

TestClass has a private in member and a method to print the private data out. My goal is to access this private memeber's value through reflection. A quick and dirty try to do so would be a code like this:

import java.lang.reflect.Field;

public class TestReflection {

      public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {

            TestClass t = new TestClass();
            t.printA();
            Field a = t.getClass().getDeclaredField("a");

            a.setInt(t, 14);
            t.printA();
      }
}

Running this will run into a java.lang.IllegalAccessException exception, which is what you would expect. However, the trick to access a private member's value is to set its accessibility. The Field class has a setAccessible method by which you can tell the VM I want to set this field's value. So, adding a single line to the same code will do the job:

import java.lang.reflect.Field;

public class TestReflection {

      public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {

            TestClass t = new TestClass();
            t.printA();
            Field a = t.getClass().getDeclaredField("a");

            a.setAccessible(true);

            a.setInt(t, 14);
            t.printA();
      }
}

Installing a security manager will prevent setting a field's accessiblity. However, you still have the option to let a specific code base do it. Yes, I am talking about security policy files. In other words, there is ways to get around this anyways.

In any events, I am not sure if this is only my illusion that private fields are not really private or there is a way to secure private values.

No comments: