Cuanto más aprendí sobre el poder de java.lang.reflect.AccessibleObject.setAccessible
, más asombrado estoy de lo que puede hacer. Esto está adaptado de mi respuesta a la pregunta ( Uso de la reflexión para cambiar el File.separatorChar final estático para las pruebas unitarias ).
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"
}
}
Puedes hacer cosas realmente escandalosas:
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"
}
}
Presumiblemente, los diseñadores de API se dan cuenta de lo abusivo que setAccessible
puede ser, pero deben haber admitido que tiene usos legítimos para proporcionarlo. Entonces mis preguntas son:
- ¿Para qué son los usos verdaderamente legítimos
setAccessible
?- ¿Podría Java haber sido diseñado para NO tener esta necesidad en primer lugar?
- ¿Cuáles serían las consecuencias negativas (si las hubiera) de tal diseño?
- ¿Puede restringirse
setAccessible
a usos legítimos únicamente?- ¿Es solo a través
SecurityManager
?- ¿Como funciona? ¿Lista blanca / lista negra, granularidad, etc.?
- ¿Es habitual tener que configurarlo en tus aplicaciones?
- ¿Puedo escribir mis clases para que sean a
setAccessible
prueba de agua independientemente de laSecurityManager
configuración?- ¿O estoy a merced de quien gestione la configuración?
- ¿Es solo a través
Supongo que una pregunta más importante es: ¿DEBO PREOCUPARME POR ESTO ???
Ninguna de mis clases tiene apariencia alguna de privacidad exigible. El patrón singleton (dejando de lado las dudas sobre sus méritos) es ahora imposible de aplicar. Como muestran mis fragmentos anteriores, incluso algunas suposiciones básicas de cómo funciona Java fundamental no están ni siquiera cerca de estar garantizadas.
¿ESTOS PROBLEMAS NO SON REALES ???
Bien, acabo de confirmar: gracias a setAccessible
, las cadenas de Java NO son inmutables.
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!"
}
}
¿Soy el único que piensa que esto es una gran preocupación?