Skip to content
Advertisement

Updating field using reflection from parent class

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.

User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement