Reputation: 63
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.
Upvotes: 5
Views: 5467
Reputation: 395
I also had problems with the given example above. For me it worked after I did not define the String as a literal but as an Object.
private static final String SECURED_FIELD = String.valueOf("SecretData");
Or
private static final String SECURED_FIELD = new String("SecretData");
Not the best solution if you want to benefit from literals but I did not have to care about it.
Upvotes: 1
Reputation: 1573
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");
Upvotes: 1
Reputation: 11433
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.
Upvotes: 6