javareflectionconstantsjava-12java-13

Change static final field in java 12+


This question is strongly related to Change private static final field using Java reflection. There, it was asked, how to change a private static final variable.


However, the answers on that question do not work in Java 12+ as you cannot access private variables of java.lang.reflect.Field using Reflection.

When you try to do it despite that, you will end up with a stack trace like:

Exception java.lang.NoSuchFieldException: modifiers
      at Class.getDeclaredField (Class.java:2412)
      at <your call of Field.class.getDeclaredField("modifiers").setAccessible(true)>

Is there any way to change such a constant in those versions?

I could imagine being possible utilizing JNI/JNA.


Solution

  • You can use Unsafe.

    public class Example
    {
        // javac will inline static final Strings, so let's say it's Object
        private static final Object changeThis = "xxx";
    
        public static void main(String... args) throws Exception
        {
            final Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
            unsafeField.setAccessible(true);
            final Unsafe unsafe = (Unsafe) unsafeField.get(null);
    
            System.out.println("before = " + changeThis);
    
            final Field ourField = Example.class.getDeclaredField("changeThis");
            final Object staticFieldBase = unsafe.staticFieldBase(ourField);
            final long staticFieldOffset = unsafe.staticFieldOffset(ourField);
            unsafe.putObject(staticFieldBase, staticFieldOffset, "it works");
    
            System.out.println("after = " + changeThis);
        }
    }
    

    Result:

    before = xxx
    after = it works