Is It Possible in Java to Access Private Fields via Reflection

How to read the value of a private field from a different class in Java?

In order to access private fields, you need to get them from the class's declared fields and then make them accessible:

Field f = obj.getClass().getDeclaredField("stuffIWant"); //NoSuchFieldException
f.setAccessible(true);
Hashtable iWantThis = (Hashtable) f.get(obj); //IllegalAccessException

EDIT: as has been commented by aperkins, both accessing the field, setting it as accessible and retrieving the value can throw Exceptions, although the only checked exceptions you need to be mindful of are commented above.

The NoSuchFieldException would be thrown if you asked for a field by a name which did not correspond to a declared field.

obj.getClass().getDeclaredField("misspelled"); //will throw NoSuchFieldException

The IllegalAccessException would be thrown if the field was not accessible (for example, if it is private and has not been made accessible via missing out the f.setAccessible(true) line.

The RuntimeExceptions which may be thrown are either SecurityExceptions (if the JVM's SecurityManager will not allow you to change a field's accessibility), or IllegalArgumentExceptions, if you try and access the field on an object not of the field's class's type:

f.get("BOB"); //will throw IllegalArgumentException, as String is of the wrong type

Set private field value with reflection

To access a private field you need to set Field::setAccessible to true. You can pull the field off the super class. This code works:

Class<?> clazz = Child.class;
Object cc = clazz.newInstance();

Field f1 = cc.getClass().getSuperclass().getDeclaredField("a_field");
f1.setAccessible(true);
f1.set(cc, "reflecting on life");
String str1 = (String) f1.get(cc);
System.out.println("field: " + str1);

Java: Accessing private field via reflection (behaviour)

Is there any limitation?

Yes - you need several JVM permissions (most notably accessDeclaredMembers and suppressAccessChecks, marked with big, bold warnings in the docs) for this to work; if your JVM's security profile is somewhat strict (say, the much-maligned applets), your code will not work because these permissions will not be available.

Does it get changed forever?

Yes, as long as your program keeps on running the fields will remain accessible (as long as you keep on using the same Field instance where you changed access permissions).

Is it bad?

Not necessarily. It allows java code to serialize and de-serialize objects with private fields, it allows complex mocking that may simplify testing, it allows you to peek into places you would not otherwise be able to peek into. However, since it breaks expectations, you should use it sparingly and make sure that users know that you require the extra permissions and "are looking under the hood". The docs (see above) state quite clearly that this is considered risky, and that it should only be allowed if you know what you are doing.

Get a private field via reflection, in Java

Change this line

name = (String) myStringField.get(obj.getClass());

to this

name = (String) myStringField.get(obj);

The get method requires an object to access the field of (unless it's a static field)

Access to private inherited fields via reflection in Java

In fact i use a complex type hierachy so you solution is not complete.
I need to make a recursive call to get all the private inherited fields.
Here is my solution

 /**
* Return the set of fields declared at all level of class hierachy
*/
public static List<Field> getAllFields(Class<?> clazz) {
return getAllFieldsRec(clazz, new ArrayList<>());
}

private static List<Field> getAllFieldsRec(Class<?> clazz, List<Field> list) {
Class<?> superClazz = clazz.getSuperclass();
if (superClazz != null) {
getAllFieldsRec(superClazz, list);
}
list.addAll(Arrays.asList(clazz.getDeclaredFields()));
return list;
}

Why is it allowed to access Java private fields via reflection?

Private is intended to prevent accidental misuse, not as a security mechanism. If you choose to bypass it then you can do so at your own risk and the assumption you know what you are doing.

Accessing private variables in Java via reflection

Figured it out. Need

field.setAccessible(true);

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


Related Topics



Leave a reply



Submit