mardi 26 décembre 2017

Java Reflection - IllegalAccessException on "set" if preceded by "get" operation

I was trying to change the value of a private static final field using reflection (yes, that's probably a very bad idea to begin with, I know). And, well, for the most part it works fine using following code:

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class A {

    public static void main(String[] args) throws ReflectiveOperationException {
        System.out.println("Before :: " + B.get());
        Field field = B.class.getDeclaredField("arr");
        field.setAccessible(true);
        // System.out.println("Peek   :: " + ((String[]) field.get(null))[0]);
        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
        field.set(null, new String[] { "Good bye, World!" });
        System.out.println("After  :: " + B.get());
    }
}

class B {
    private static final String[] arr = new String[] { "Hello, World!" };

    public static String get() {
        return arr[0];
    }
}

Which prints as expected:

Before :: Hello, World!
After  :: Good bye, World!

Problems arise when I try to get the field value via reflection prior to setting it. That is, if I uncomment the commented line in above sample, I get the following:

Before :: Hello, World!
Peek   :: Hello, World!
Exception in thread "main" java.lang.IllegalAccessException: Can not set static final [Ljava.lang.String; field B.arr to [Ljava.lang.String;
        at sun.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:76)
        at sun.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:80)
        at sun.reflect.UnsafeQualifiedStaticObjectFieldAccessorImpl.set(UnsafeQualifiedStaticObjectFieldAccessorImpl.java:77)
        at java.lang.reflect.Field.set(Field.java:764)
        at A.main(A.java:14)

Why is this happening?? I tried to set again the accessible flag after the call to get but it doesn't help. I tried many other things that don't seem to help either...

Thanks for your help!





Aucun commentaire:

Enregistrer un commentaire