The more I learned about the power of java.lang.reflect.AccessibleObject.setAccessible
, the more astonished I am at what it can do. This is adapted from my answer to the question (Using reflection to change static final File.separatorChar for unit testing).
import java.lang.reflect.*;
public class EverythingIsTrue {
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 {
setFinalStatic(Boolean.class.getField("FALSE"), true);
System.out.format("Everything is %s", false); // "Everything is true"
}
}
You can do truly outrageous stuff:
public class UltimateAnswerToEverything {
static Integer[] ultimateAnswer() {
Integer[] ret = new Integer[256];
java.util.Arrays.fill(ret, 42);
return ret;
}
public static void main(String args[]) throws Exception {
EverythingIsTrue.setFinalStatic(
Class.forName("java.lang.Integer$IntegerCache")
.getDeclaredField("cache"),
ultimateAnswer()
);
System.out.format("6 * 9 = %d", 6 * 9); // "6 * 9 = 42"
}
}
Presumably the API designers realize how abusable setAccessible
can be, but must have conceded that it has legitimate uses to provide it. So my questions are:
- What are the truly legitimate uses for
setAccessible
?- Could Java has been designed as to NOT have this need in the first place?
- What would the negative consequences (if any) of such design be?
- Can you restrict
setAccessible
to legitimate uses only?- Is it only through
SecurityManager
?- How does it work? Whitelist/blacklist, granularity, etc?
- Is it common to have to configure it in your applications?
- Can I write my classes to be
setAccessible
-proof regardless ofSecurityManager
configuration?- Or am I at the mercy of whoever manages the configuration?
- Is it only through
I guess one more important question is: DO I NEED TO WORRY ABOUT THIS???
None of my classes have any semblance of enforceable privacy what-so-ever. The singleton pattern (putting doubts about its merits aside) is now impossible to enforce. As my snippets above show, even some basic assumptions of how Java fundamental works is not even close to being guaranteed.
ARE THESE PROBLEMS NOT REAL???
Okay, I just confirmed: thanks to setAccessible
, Java strings are NOT immutable.
import java.lang.reflect.*;
public class MutableStrings {
static void mutate(String s) throws Exception {
Field value = String.class.getDeclaredField("value");
value.setAccessible(true);
value.set(s, s.toUpperCase().toCharArray());
}
public static void main(String args[]) throws Exception {
final String s = "Hello world!";
System.out.println(s); // "Hello world!"
mutate(s);
System.out.println(s); // "HELLO WORLD!"
}
}
Am I the only one who thinks this is a HUGE concern?