532 votes

Comment lire un champ privé en Java?

J'ai une classe mal conçue dans un tiers JAR et j'ai besoin d'accéder à l'un de ses champs privés . Par exemple,

 class IWasDesignedPoorly {
    private Hashtable stuffIWant;
}

IWasDesignedPoorly obj = ...;
 

Comment puis-je utiliser la réflexion pour obtenir la valeur de stuffIWant ?

719voto

oxbow_lakes Points 70013

Pour accéder aux champs privés, vous avez besoin pour obtenir à partir de la classe est déclarée champs, puis de les rendre accessibles:

Field f = obj.getClass().getDeclaredField("stuffIWant"); //NoSuchFieldException
f.setAccessible(true);
Hashtable iWantThis = (Hashtable) f.get(obj); //IllegalAccessException

EDIT: comme l'a été commenté par aperkins, tant l'accès au champ, réglage de l'accessibilité et de la récupération de la valeur de tous les jeter Exceptions, bien que le seul checked exceptions vous besoin d'être conscient de sont commentés ci-dessus.

L' NoSuchFieldException pourrait être levée si vous avez demandé un champ par un nom qui ne correspond pas à une déclaration de terrain.

obj.getClass().getDeclaredField("misspelled"); //will throw NoSuchFieldException

L' IllegalAccessException pourrait être levée si le champ n'était pas accessible (par exemple, s'il est privé et n'a pas été rendu accessible par manquer l' f.setAccessible(true) ligne de.

L' RuntimeExceptions qui pourraient être projetés sont soit SecurityExceptions (si la JVM SecurityManager ne vous permettra pas de modifier un champ d'accessibilité), ou IllegalArgumentExceptions, si vous essayez d'accéder au champ sur un objet n'est pas de la classe du type:

f.get("BOB"); //will throw IllegalArgumentException, as String is of the wrong type

183voto

yegor256 Points 21737

Essayez FieldUtils depuis apache commons-lang3:

 FieldUtils.readField(object, fieldName, true);
 

28voto

Brian Agnew Points 143181

La réflexion n'est pas la seule façon.

Une solution alternative consiste à extraire de la classe à partir de l' .jar, décompiler à l'aide de (disons) de Jode ou Jad, modifiez le champ (ou ajouter un accesseur), et de recompiler contre l'original .jar. Ensuite, mettre le nouveau .la classe à l'avance de l' .jar dans le classpath, ou réinsérez-la dans l' .jar. (le pot utilitaire vous permet d'extraire et de le réinsérer à un existant .jar)

Cela nécessite l' .jar de ne pas être signé, bien sûr.

18voto

lucas Points 4344

Une autre option qui n'a pas encore été mentionnée: utilisez Groovy . Groovy vous permet d'accéder aux variables d'instance privées comme un effet secondaire de la conception de la langue. Que vous ayez ou non un getter pour le terrain, vous pouvez simplement utiliser

 def obj = new IWasDesignedPoorly()
def hashTable = obj.getStuffIWant()
 

5voto

Laurence Gonsalves Points 50783

Comme le mentionne oxbow_lakes, vous pouvez utiliser la réflexion pour contourner les restrictions d'accès (en supposant que votre SecurityManager vous le permette).

Cela dit, si cette classe est si mal conçue qu'elle vous permet de recourir à ce genre de piratage, vous devriez peut-être chercher une alternative. Bien sûr, ce petit hack pourrait vous sauver quelques heures maintenant, mais combien cela vous coûtera-t-il sur la route?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X