Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Reflection, change private static final field didn't do anything

I'm trying to change a private static final field with Java Reflection. But it just fail. Did someone have an idea ?

Here's my code :

public class SecuredClass {
    private static final String securedField = "SecretData";
    public static String getSecretData() { return securedField; }
}

public class ChangeField {
    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);
    }

    public static void main(String args[]) throws Exception
    {
        System.out.println("Before = " + SecuredClass.getSecretData());

        Field stringField = SecuredClass.class.getDeclaredField("securedField");
        stringField.setAccessible(true);
        setFinalStatic(stringField, "Screwed Data!");


        System.out.println("After = " + Java_FileMerger_Main.getSecretData());
    }
}

And here's my output :

Before = SecretData
After = SecretData

I've tried to remove the SecurityManager with System.setSecurityManager(null); But it didn't change anything. I know this is evil, but i want to get it work. I hope someone could help me.

like image 618
Nicnl Avatar asked Feb 22 '12 08:02

Nicnl


People also ask

Can a static final variable be changed?

Finally, with the static final variable, it's both the same for each class and it can't be changed after it's initialized.

How do I change the value of the final static variable in Java?

In Java, non-static final variables can be assigned a value either in constructor or with the declaration. But, static final variables cannot be assigned value in constructor; they must be assigned a value with their declaration.

Is private static final a constant?

private static final will be considered as constant and the constant can be accessed within this class only. Since, the keyword static included, the value will be constant for all the objects of the class. private final variable value will be like constant per object.

How can a final field be set to a value in Java?

When a field is defined as final , it has to be initialised when the object is constructed, i.e. you're allowed to assign value to it inside a constructor. A static field belongs to the class itself, i.e. one per class. A static final field is therefore not assignable in the constructor which is one per object.


2 Answers

The semantics of changing final fields via reflection are not defined (cf. specification). It is not guaranteed that a reflective write to a final field will ever be seen when reading from the field.

Especially with static final fields which have a constant assigned (as in your case), the compiler will often inline the constant and thus the field won't be accessed at all during runtime (only when you use reflection).

The SecurityManager is not relevant here. If using reflection would be forbidden by a SecurityManager, the operation would throw an exception, and not fail silently.

The answers to the question Change private static final field using Java reflection provide some more detail, including an example where you can see in the byte code that constants get inlined.

like image 64
Philipp Wendler Avatar answered Oct 23 '22 00:10

Philipp Wendler


There is a work around for this. if you set the value of the private static final filed in the static {} block it will work because it will not inline the field:

private static final String MY_FIELD;

static {
    MY_FIELD = "SomeText"
}

...

Field field = VisitorId.class.getDeclaredField("MY_FIELD");

field.setAccessible(true);
field.set(field, "fakeText");
like image 31
Joan P.S Avatar answered Oct 23 '22 01:10

Joan P.S