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.
Finally, with the static final variable, it's both the same for each class and it can't be changed after it's initialized.
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.
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.
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.
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.
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");
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With