Java Reflection: accesso a metodi e campi privati
DOMANDA:
Come si può accedere da un classe generica ai metodi e alle variabili di istanza private di un'altra classe?
RISPOSTA:
Genericamente non è possibile accedere ai campi o metodi privati di un'altra classe. Ma genericamente non vuol dire in modo assoluto! Infatti, grazie alla Reflection Java possiamo accedere ai campi privati di un'altra classe.
Analizziamo alcuni metodi che ci mette a disposizione la classe java.lang.Class:
- getFields(): permette di recuperare la lista di tutti i campi pubblici della classe e della sua superclasse;
- getDeclaredFields(): fornisce la lista di tutti i campi presenti nella classe (senza distinzione di visibilità);
- getDeclaredMethods(): come sopra ma applicato ai metodi;
- getDeclaredField(String nome): restituisce il Field indicato come parametro (senza distinzione di visibilità);
- getDeclaredMethos(String nome): restituisce il Method indicato come parametro (senza distinzione di visibilità).
Guardiamo l'esempio, prima con la ClassePrivata da analizzare:
package reflection; public class ClassePrivata { public int publicValue = 99999; protected int protectedValue = 200; int packageProtectedValue = 10000; private int secretValue = 12345; public String getPublicValue(){ return "Il valore pubblico è: " +publicValue; } protected String getProtectedValue(){ return "Il valore protected è: " +protectedValue; } String getPackageProtectedValue(){ return "Il valore packageProtected è: "+packageProtectedValue; } private String getSecretValue(){ return "Il valore segreto è: " +secretValue; } }
E poi con la classe analizzatrice ElencoCampiMetodi:
package reflection; import java.util.Arrays; public class ElencoCampiMetodi { public static void main(String args[]) throws ClassNotFoundException { Class<ClassePrivata> pvtClass = (Class<ClassePrivata>) Class.forName("reflection.ClassePrivata"); //getFields() non restituisce i campi privati System.out.println("Fields: " + Arrays.toString(pvtClass.getFields())); //getDeclaredFields() restituisce sia i campi privati che non System.out.println("Declared Fields: " + Arrays.toString(pvtClass.getDeclaredFields())); //getDeclaredMethods() restituisce sia i metodi privati che non System.out.println("Declared methods: " + Arrays.toString(pvtClass.getDeclaredMethods())); } }
L'output, come previsto, sarà:
Fields: [public int reflection.ClassePrivata.publicValue]
Declared Fields: [public int reflection.ClassePrivata.publicValue, int reflection.ClassePrivata.packageProtectedValue, private int reflection.ClassePrivata.secretValue]
Declared methods: [private java.lang.String reflection.ClassePrivata.getSecretValue(), public java.lang.String reflection.ClassePrivata.getPublicValue()]
Declared Fields: [public int reflection.ClassePrivata.publicValue, int reflection.ClassePrivata.packageProtectedValue, private int reflection.ClassePrivata.secretValue]
Declared methods: [private java.lang.String reflection.ClassePrivata.getSecretValue(), public java.lang.String reflection.ClassePrivata.getPublicValue()]
Passiamo ora al recupero vero e proprio del valore di un campo privato e all'esecuzione di un metodo privato:
public class PrivateAccessTest { public static void main(String args[]) throws ClassNotFoundException { Class<ClassePrivata> pvtClass = (Class<ClassePrivata>) Class.forName("reflection.ClassePrivata"); try { ClassePrivata myClassPvt = new ClassePrivata(); // recupero il campo privato e lo rendo accessibile Field campoPrivato = pvtClass.getDeclaredField("secretValue"); campoPrivato.setAccessible(true); // recupero il valore del campo privato int valore = campoPrivato.getInt(myClassPvt); // stampo il campo privato e il suo valore System.out.println("Campo Privato: " + campoPrivato); System.out.println("Valore campo privato: " + valore); // recupero il metodo privato e lo rendo accessibile Method metodoPrivato = pvtClass.getDeclaredMethod("getSecretValue"); metodoPrivato.setAccessible(true); // recupero il valore di ritorno del metodo privato String result = (String) metodoPrivato.invoke(myClassPvt); System.out.println(result); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchFieldException | SecurityException | NoSuchMethodException e) { e.printStackTrace(); } } }
L'output anche in questo caso ci darà conferma del risultato voluto:
Campo Privato: private int reflection.ClassePrivata.secretValue
Valore campo privato: 12345
Il valore segreto è: 12345
Valore campo privato: 12345
Il valore segreto è: 12345
NOTA: per accedere ad un campo o metodo privato dobbiamo renderlo accessibile grazie al metodo setAccessible(true). Se non lo facessimo, appena tentiamo l'accesso al campo o al metodo ci ritroveremo un'eccezione di questo tipo:
java.lang.IllegalAccessException:
Class reflection.PrivateAccessTest can not access a member of class reflection.ClassePrivata with modifiers "private"
Class reflection.PrivateAccessTest can not access a member of class reflection.ClassePrivata with modifiers "private"
NOTA FINALE: il codice utilizza il multicatch introdotto da Java 7. Se state utilizzando una versione precedente di Java dovete sostituirlo con il catch alla vecchia maniera! Per ulteriori informazioni sul multicatch vi invito a leggere questo post.
Commenti
Posta un commento