1

I'm trying to overwrite the value of a non-static final field through Reflection in Java 17.

As far as I know, you can no longer do the following trick starting with Java 12 and above:

import java.lang.reflect.*;

class Foo {
private final String bar;

    public Foo(String bar) {
        this.bar = bar;
    }
    
    public String getBar() {
        return this.bar;
    }

}

public class Example {

    public static void main(String[] args) {
        Foo foo = new Foo("foobar");
        System.out.println(foo.getBar());
    
        try {
            Field field = foo.getClass().getDeclaredField("bar");
            field.setAccessible(true);
            Field modifiers = field.getClass().getDeclaredField("modifiers");
            modifiers.setAccessible(true);
            modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL);
        } catch (Exception e) {
            e.printStackTrace();    
        }
    
        System.out.println(foo.getBar());
    }

}

When I run this in Java 17, the following exception is thrown:

foobar java.lang.NoSuchFieldException: modifiers    at java.base/java.lang.Class.getDeclaredField(Class.java:2610)  at Example.main(Example.java:24) foobar

And the value of 'bar' remains unchanged.

Is there an equivalent method of overwriting a final field for the newer versions of Java? A quick search in Google didn't yield anything different from the above solution. The only thing I learned was that it is impossible to overwrite a static final field, while it's still possible to overwrite a non-static final field through Reflection, but I couldn't find out how.

godfather
  • 11
  • 1
  • 3
  • You don't need to modify the `modifiers` field. Just remove the three lines: `Field modifiers = field.getClass().getDeclaredField("modifiers");`, `modifiers.setAccessible(true);` and `modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL);`. – Johannes Kuhn Nov 02 '22 at 15:58
  • @JohannesKuhn how else do you clear the "final" flag from the "bar" field? – TWiStErRob Jun 02 '23 at 11:35
  • Dear future reflection adventurer, you might want to look at this question: https://stackoverflow.com/q/56039341/253468 – TWiStErRob Jun 02 '23 at 13:04
  • 1
    @TWiStErRob You don't need to clear the `final` modifier - `final` instance variables can be set using `Field.set` if you called `setAccessible(true)` on it before. – Johannes Kuhn Jun 02 '23 at 13:37

1 Answers1

-1

This should work:

 Field field = foo.getClass().getDeclaredField("bar");
 field.setAccessible(true);
 field.set(foo, "changedBar");
  • no, this doesn't work – jprusakova May 18 '23 at 23:37
  • @jprusakova No, works fine: https://www.ideone.com/1RvmS9 – Johannes Kuhn Jun 02 '23 at 13:46
  • @JohannesKuhn That sample seems to be Java 12? The OP was asking about Java 17, where I can confirm the above code doesn't work. – Will Hains Jun 06 '23 at 12:15
  • @WillHains Is the field `static`? Then it does not work - [you can't change static final fields](https://gist.github.com/DasBrain/ca16053f8e073c8a883bee66302c2fee). You never could do that reliably. Otherwise, you can change non-static final fields (except final fields of records/hidden classes) this way. Works in Java 8 - Java 20. – Johannes Kuhn Jun 06 '23 at 12:58