Cuanto más aprendí sobre el poder de java.lang.reflect.AccessibleObject.setAccessible
, más me asombré de lo que puede hacer. Esto se ha adaptado de mi respuesta a la pregunta (Using reflection to change static final File.separatorChar for unit testing).¿Cómo limitar el acceso inaccesible a usos "legítimos"?
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"
}
}
Puede hacer cosas verdaderamente indignante:
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"
}
}
Es de suponer que los diseñadores de la API de darse cuenta de lo que se puede abusar setAccessible
puede ser, pero debe de haber admitido que tiene usos legítimos que le proporcione. Entonces mis preguntas son:
- ¿Cuáles son los usos verdaderamente legítimos para
setAccessible
?- ¿Podría Java haberse diseñado para NO tener esta necesidad en primer lugar?
- ¿Cuáles serían las consecuencias negativas (si las hay) de dicho diseño?
- ¿Se puede restringir
setAccessible
solo para usos legítimos?- ¿Es solo a través de
SecurityManager
?- ¿Cómo funciona? ¿Lista blanca/lista negra, granularidad, etc.?
- ¿Es común tener que configurarlo en sus aplicaciones?
- puedo escribir mis clases para ser
setAccessible
-proof independientemente de la configuraciónSecurityManager
?- ¿O estoy a merced de quien maneja la configuración?
- ¿Es solo a través de
supongo una pregunta más importante es: ¿Es necesario que preocuparse por esto ???
Ninguna de mis clases tiene ninguna apariencia de privacidad exigible como tal. El patrón singleton (dejando de lado las dudas sobre sus méritos) ahora es 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 ser garantizadas.
¿ESTOS PROBLEMAS NO SON REALES?
Vale, acaba de confirmar: gracias a setAccessible
, cadenas de Java son NO inmutable.
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?
¡Debería ver lo que pueden hacer en C++! (Ah, y probablemente C#.) –
+1 para la pregunta increíble ... :) – Legend