How to Access Private Methods and Private Data Members via Reflection

How do I access private methods and private data members via reflection?

1) How can I access the private methods and the private data members?

You can do it with a little help of the setAccessible(true) method:

class Dummy{
private void foo(){
System.out.println("hello foo()");
}
private int i = 10;
}

class Test{
public static void main(String[] args) throws Exception {
Dummy d = new Dummy();

/*--- [INVOKING PRIVATE METHOD] ---*/
Method m = Dummy.class.getDeclaredMethod("foo");
//m.invoke(d); // Exception java.lang.IllegalAccessException
m.setAccessible(true);//Abracadabra
m.invoke(d); // Now it's OK

/*--- [GETING VALUE FROM PRIVATE FIELD] ---*/
Field f = Dummy.class.getDeclaredField("i");
//System.out.println(f.get(d)); // Not accessible now
f.setAccessible(true); // Abracadabra
System.out.println(f.get(d)); // Now it's OK

/*--- [SETTING VALUE OF PRIVATE FIELD] ---*/
Field f2 = Dummy.class.getDeclaredField("i");
//f2.set(d,20); // Not accessible now
f2.setAccessible(true); // Abracadabra
f2.set(d, 20); // Now it's OK
System.out.println(f2.get(d));
}
}

2) Is it possible to access a local variable via reflection?

No. Local variables cannot be accessed outside of a block in which they were created (someone could say that you can assign such a variable to a field like field = localVariable; and later access such a field via reflection, but this way we will be accessing the value, not the variable).

3) Is there any way to prevent anyone from accessing private constructors, methods, and data members?

I think for constructors or methods you could use stacktrace to check if it was invoked by Reflection.

For fields I can't find a solution to prevent accessing them via reflection.

[WARNING: This is not approved by anyone. I just wrote it inspired by your question.]

class Dummy {
private void safeMethod() {
StackTraceElement[] st = new Exception().getStackTrace();
// If a method was invoked by reflection, the stack trace would be similar
// to something like this:
/*
java.lang.Exception
at package1.b.Dummy.safeMethod(SomeClass.java:38)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
-> at java.lang.reflect.Method.invoke(Method.java:601)
at package1.b.Test.main(SomeClass.java:65)
*/
//5th line marked by "->" is interesting one so I will try to use that info

if (st.length > 5 &&
st[4].getClassName().equals("java.lang.reflect.Method"))
throw new RuntimeException("safeMethod() is accessible only by Dummy object");

// Now normal code of method
System.out.println("code of safe method");
}

// I will check if it is possible to normally use that method inside this class
public void trySafeMethod(){
safeMethod();
}

Dummy() {
safeMethod();
}
}

class Dummy1 extends Dummy {}

class Test {
public static void main(String[] args) throws Exception {
Dummy1 d1 = new Dummy1(); // safeMethod can be invoked inside a superclass constructor
d1.trySafeMethod(); // safeMethod can be invoked inside other Dummy class methods
System.out.println("-------------------");

// Let's check if it is possible to invoke it via reflection
Method m2 = Dummy.class.getDeclaredMethod("safeMethod");
// m.invoke(d);//exception java.lang.IllegalAccessException
m2.setAccessible(true);
m2.invoke(d1);
}
}

Output from Test main method:

code of safe method
code of safe method
-------------------
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at package1.b.Test.main(MyClass2.java:87)
Caused by: java.lang.RuntimeException: method safeMethod() is accessible only by Dummy object
at package1.b.Dummy.safeMethod(MyClass2.java:54)
... 5 more

How do I use reflection to access a private method?

getDeclaredMethod needs you to pass the parameter types so that it can resolve overloaded methods.

Since your foo method has a single parameter of type String, the following should work:

Method m = Dummy.class.getDeclaredMethod("foo", String.class);

And of course you also need to change the invoke call to pass a string.

Why is it possible to access private data/classes via reflection?

Sometimes you need access to private fields for unit testing. Such as testing small private functions in a class that is used internally but should not be called directly. Other times you may want to check if an internal data structure contains the correct data.

If you're using reflection as a means to access private data for other reasons you probably have to come up with a good reason to do so since most people reviewing your code (if any) will probably notice and that will come up as a red flag (the field is private for a reason right?).

Choice 2 was probably made to allow this use of reflection (which can be disabled in your non-debug builds).

If we can access private data members using Accessors than why cant we access private methods?

You can access private method via public method. This is sometimes used to wrap complicated private method and expose simpler, public API.

class Delegator {

private void doPrivateStuff(int param) { ... }

public void doStuffOnce() {
doPrivateStuff(1);
}

public void doStuffIfConditionIsMet() {
if(condition) {
doPrivateStuff(1);
}
}
}

You can also access private methods using reflection.
http://tutorials.jenkov.com/java-reflection/private-fields-and-methods.html

Any way to Invoke a private method?

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

Accessing private variables in Java via reflection

Figured it out. Need

field.setAccessible(true);

Use Reflection to Write test for private methods

But the question is how much is this way okay to write test for private methods with using of reflection?

Is there a better way to achieve this goal?

The most common approach is to abandon that goal.

Historically, the focus of TDD has been on verifying behaviors, not implementation details. Part of the point was that the tests give us the freedom to change the internal design of the code, confidently, because the tests will alert us to any unintended changes in behavior.

So if we need a test to ensure that the logic in some private method is correct, we find a use case for the public API that depends on that logic, and write tests that measure the behavior of the public API.

We can calibrate the test by injecting a temporary fault into the private method, and verifying that the test detects the fault.

Having done that, we have the option of refactoring the code by inlining the private method; all of the tests should still pass in that case, because we haven't changed the behavior of the test subject -- we've just moved the details around.

If you are going to be aggressively working to improve the internal design of your application, then you need tests that are decoupled from that internal design.



Related Topics



Leave a reply



Submit