Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 17 Reflection issue

Tags:

java

Try to call this function to set the private static final value. This reflection code works on Java 11, but does not work for 17. Hit a no such field exception error.

    public static void setFinalStatic(Field field, Object newValue) throws Exception {
        field.setAccessible(true);
        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
        field.set(null, newValue);
    }
java.lang.NoSuchFieldException: modifiers
    at java.base/java.lang.Class.getDeclaredField(Class.java:2610)

I did try --add-opens java.base/java.lang.reflect=ALL-UNNAMED, but it's not working.

Any solution or work around for this??

like image 314
Kevin Chuang Avatar asked Feb 20 '26 21:02

Kevin Chuang


2 Answers

It's no more directly possible since version 12, for this issue .

For the java 17, I've used this workaround:

    public static void setFinalStatic(Field field, Object newValue) throws Exception {
        field.setAccessible(true);
        Method getDeclaredFields0 = Class.class.getDeclaredMethod("getDeclaredFields0", boolean.class);
        getDeclaredFields0.setAccessible(true);
        Field[] fields = (Field[]) getDeclaredFields0.invoke(Field.class, false);
        Field modifiersField = null;
        for (Field each : fields) {
            if ("modifiers".equals(each.getName())) {
                modifiersField = each;
                break;
            }
        }
        modifiersField.setAccessible(true);
        modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
        field.set(null, newValue);
    }

To run, you should add these arguments:

--add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.lang.reflect=ALL-UNNAMED

like image 76
Antonio Berritto Avatar answered Feb 27 '26 10:02

Antonio Berritto


Java9 broke reflection and as the version number goes up, the breaks get worse. Essentially, accessing non-exported elements of other modules (modules introduced in java 9) does not work without adding a bevy of complicated --add-opens lines when starting the java executable. "modules" as a concept did not exist prior to java9, hence, the java8 and below javadoc makes no mention of any of this.

The vast majority of apps and libraries that warn that they do not work on newer JVMs is because of this backwards incompatible change to the JVM.

The solution is one of four options:

  1. The usual one: Downgrade to JDK8 or 11.
  2. Do the --add-opens dance.
  3. Do some light hackery using e.g. Unsafe. For advanced users only, and note that this is likely to mean near future JVM versions will break again.
  4. Figure out a way to do it without having to reflect your way into non-exported parts of other modules. Here, specifically.. just call field.getModifiers().
like image 29
rzwitserloot Avatar answered Feb 27 '26 10:02

rzwitserloot



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!