I have a Parent class that has a method that uses reflection to retrieve and update fields. This method will be called by the child class
package com.torchai.service.common.response; import java.lang.reflect.Field; public class TestReflection { private String foo; public void update() throws IllegalAccessException { final Field[] fields = getClass().getDeclaredFields(); for (final Field f : fields) { // f.setAccessible(true); // final Object value = response.get(f.getName()); Object value = "new value"; f.set(this, value); } } public static void main(final String[] args) throws IllegalAccessException { final TestReflection t = new TestReflection() { private String abc; }; t.update(); } }
When the child class (in this case, an anonymous class) calls the method, which is inherited form the parent, the value of this
is the child class. Because of that, I thought there would be no problem in retrieving and setting private fields. It turns out that getDeclaredFields()
can retrieve private
fields, but Field.set()
cannot update them, unless I setAccessible
to true. Is this correct behavior? Why can’t the child class set its own fields? If I can see the field (i.e., I can retrieve the private field) shouldn’t I be able to update it?
The exception I get is
java.lang.IllegalAccessException: Class com.torchai.service.common.response.TestReflection can not access a member of class com.torchai.service.common.response.TestReflection$1 with modifiers "private"
Note that it implies that it is the parent class that it trying to access the child class. Why is the parent class being considered the caller?
If I change the main method to eliminate the use of the child class
TestReflection t = new TestReflection(); t.update()
then it works as expected. The class is updating its own fields, so setAccessbile
is not necessary
Advertisement
Answer
The code that is trying to access the field is inside the class TestReflection
and that is all that matters. There is no indicator that the subclass is willing to grant its superclass access to its field, as private
implies no access from any other class. The subclass is just invoking a method update()
of its superclass without knowing what that method will do internally, so it’s not the subclass trying to access the subclass’s field here.
To be more precise, in your specific example, the subclass is a nested class of the superclass, so accessing each other’s private
members is allowed, but you hit an old flaw of Reflection that existed as long as nested classes exist. When you compile your example with target JDK 11 or newer, this specific example will work.
But for top level classes, private
means that no other class can access it (without enabling access override first), regardless of whether it is a subclass or superclass of the the declaring class. Which seems to be your actual question.
Note that using a construct like getClass().getDeclaredFields()
is rather unusual. Even more is looping over the discovered fields and just setting all of them. Normally, you want to know what class and field you’re accessing. In your example, you’re trying to set the field abc
of the subclass but when you change the example to new TestReflection().update()
, you’re setting the field foo
of TestReflection
instead.