Più ho imparato a conoscere la potenza di java.lang.reflect.AccessibleObject.setAccessible
, più mi stupisco di quello che può fare. Questo è adattato dalla mia risposta alla domanda (Using reflection to change static final File.separatorChar for unit testing).Come limitare setAccessible ai soli usi "legittimi"?
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"
}
}
È possibile fare cose veramente scandaloso:
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"
}
}
Presumibilmente i progettisti API rendono conto di quanto abusable setAccessible
può essere, ma deve avere ammesso che esso ha usi legittimi di fornirle. Quindi le mie domande sono:
- Quali sono gli usi veramente legittimi per
setAccessible
?- Java potrebbe essere stato progettato in modo da NON avere questo bisogno in primo luogo?
- Quali sarebbero le conseguenze negative (se presenti) di tale progettazione?
- È possibile limitare lo
setAccessible
solo a usi legittimi?- È solo tramite
SecurityManager
?- Come funziona? Lista bianca/lista nera, granularità, ecc.?
- È comune doverlo configurare nelle applicazioni?
- Posso scrivere le mie classi di essere
setAccessible
-proof indipendentemente dalla configurazioneSecurityManager
?- O sono alla mercé di chi gestisce la configurazione?
- È solo tramite
Credo che ancora una domanda importante è: DEVO preoccupare di questo ???
Nessuna delle mie classi ha una parvenza di privacy applicabile che mai. Il modello singleton (mettendo da parte i dubbi sui suoi meriti) è ora impossibile da far rispettare. Come mostrano i miei frammenti sopra, anche alcune ipotesi di base su come funziona il fondamentale di Java non è nemmeno vicino ad essere garantito.
QUESTI PROBLEMI NON SONO REALI ???
Okay, ho appena confermato: grazie alla setAccessible
, stringhe Java sono NON immutabile.
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!"
}
}
Sono l'unico a ritenere che questa sia una preoccupazione ENORME?
Dovresti vedere cosa possono fare in C++! (Oh, e probabilmente C#.) –
+1 per la fantastica domanda ... :) – Legend