Pour accéder aux champs privés, vous devez les obtenir à partir des champs déclarés de la classe, puis les rendre accessibles:
Field f = obj.getClass().getDeclaredField("stuffIWant"); //NoSuchFieldException
f.setAccessible(true);
Hashtable iWantThis = (Hashtable) f.get(obj); //IllegalAccessException
EDIT : comme l'a commenté aperkins , à la fois accéder au champ, le définir comme accessible et récupérer la valeur peut lancer Exception
s, bien que les seules exceptions vérifiées dont vous devez être conscient soient commentées ci-dessus.
Le NoSuchFieldException
serait levé si vous demandiez un champ par un nom qui ne correspondait pas à un champ déclaré.
obj.getClass().getDeclaredField("misspelled"); //will throw NoSuchFieldException
Le IllegalAccessException
serait jeté si le champ n'était pas accessible (par exemple, s'il est privé et n'a pas été rendu accessible en manquant la f.setAccessible(true)
ligne.
Les RuntimeException
s qui peuvent être levés sont soit SecurityException
s (si la machine virtuelle Java SecurityManager
ne vous permet pas de modifier l'accessibilité d'un champ), soit IllegalArgumentException
s, si vous essayez d'accéder au champ sur un objet qui n'est pas du type de la classe du champ:
f.get("BOB"); //will throw IllegalArgumentException, as String is of the wrong type
getDeclaredField()
ne trouve pas les champs s'ils sont définis dans les classes parentes - vous devez également parcourir la hiérarchie des classes parentes, en appelantgetDeclaredField()
chacune, jusqu'à ce que vous trouviez une correspondance (après laquelle vous pouvez appelersetAccessible(true)
) ou que vous atteigniezObject
.private
champs. Il empêche l'accès accidentel.Essayez
FieldUtils
avec apache commons-lang3:la source
La réflexion n'est pas le seul moyen de résoudre votre problème (qui consiste à accéder aux fonctionnalités / comportements privés d'une classe / d'un composant)
Une autre solution consiste à extraire la classe du .jar, à la décompiler en utilisant (disons) Jode ou Jad , à modifier le champ (ou à ajouter un accesseur) et à le recompiler avec le .jar d'origine. Mettez ensuite la nouvelle .class devant le
.jar
dans le chemin de classe, ou réinsérez-la dans le.jar
. (l'utilitaire jar vous permet d'extraire et de réinsérer dans un .jar existant)Comme indiqué ci-dessous, cela résout le problème plus large de l'accès / la modification de l'état privé plutôt que l'accès / la modification d'un champ.
Il faut pour cela de
.jar
ne pas être signé, bien sûr.la source
Une autre option qui n'a pas encore été mentionnée: utilisez Groovy . Groovy vous permet d'accéder à des variables d'instance privées comme effet secondaire de la conception du langage. Que vous ayez ou non un getter pour le terrain, vous pouvez simplement utiliser
la source
En utilisant la réflexion en Java, vous pouvez accéder à tous les
private/public
champs et méthodes d'une classe à une autre. Mais selon la documentation Oracle dans la section inconvénients, ils ont recommandé que:"Étant donné que la réflexion permet au code d'effectuer des opérations qui seraient illégales dans un code non réfléchissant, telles que l'accès à des champs et des méthodes privés, l'utilisation de la réflexion peut entraîner des effets secondaires inattendus, qui peuvent rendre le code dysfonctionnel et détruire la portabilité. Code réfléchissant brise les abstractions et peut donc changer de comportement avec les mises à niveau de la plate-forme "
voici des extraits de code pour illustrer les concepts de base de la réflexion
Reflection1.java
Reflection2.java
J'espère que cela vous aidera.
la source
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 fait recourir à un tel piratage, vous devriez peut-être chercher une alternative. Bien sûr, ce petit hack pourrait vous faire économiser quelques heures maintenant, mais combien cela vous coûtera-t-il sur la route?
la source
Utilisez le framework Soot Java Optimization pour modifier directement le bytecode. http://www.sable.mcgill.ca/soot/
Soot est entièrement écrit en Java et fonctionne avec les nouvelles versions de Java.
la source
Vous devez effectuer les opérations suivantes:
la source
Si vous utilisez Spring, ReflectionTestUtils fournit des outils pratiques qui vous aident ici avec un minimum d'effort. Il est décrit comme "destiné à être utilisé dans des scénarios de tests unitaires et d'intégration" . Il existe également une classe similaire nommée ReflectionUtils, mais celle-ci est décrite comme "destinée uniquement à un usage interne" - voir cette réponse pour une interprétation de ce que cela signifie.
Pour traiter l'exemple publié:
la source
ReflectionTestUtils
comme dans mon expérience, je n'ai jamais eu besoin de faire ce genre de chose dans une situation de test.)Juste une note supplémentaire sur la réflexion: j'ai observé dans certains cas spéciaux, lorsque plusieurs classes du même nom existent dans des packages différents, que la réflexion telle qu'utilisée dans la première réponse peut ne pas sélectionner la classe correcte dans l'objet. Donc, si vous savez quelle est la package.class de l'objet, il est préférable d'accéder à ses valeurs de champ privé comme suit:
(Ceci est l'exemple de classe qui ne fonctionnait pas pour moi)
la source
Vous pouvez utiliser @JailBreak de Manifold pour une réflexion Java directe et sécurisée:
@JailBreak
déverrouille lafoo
variable locale dans le compilateur pour un accès direct à tous les membres deFoo
la hiérarchie.De même, vous pouvez utiliser la méthode d'extension jailbreak () pour une utilisation ponctuelle:
Grâce à la
jailbreak()
méthode, vous pouvez accéder à n'importe quel membre deFoo
la hiérarchie.Dans les deux cas, le compilateur résout l'accès au champ pour vous en toute sécurité, comme s'il s'agissait d'un champ public, tandis que Manifold génère un code de réflexion efficace pour vous sous le capot.
En savoir plus sur le collecteur .
la source
C'est assez simple avec l'outil XrayInterface . Il suffit de définir les getters / setters manquants, par exemple
et xray votre pauvre projet conçu:
En interne, cela repose sur la réflexion.
la source
Essayez de contourner le problème pour le cas, le type dont vous voulez définir / obtenir des données est l'une de vos propres classes.
Créez simplement un
public setter(Field f, Object value)
etpublic Object getter(Field f)
pour cela. Vous pouvez même faire quelques vérifications de sécurité par vous-même à l'intérieur de ces fonctions membres. Par exemple pour le passeur:Bien sûr, vous devez maintenant trouver le
java.lang.reflect.Field
forsString
avant de définir la valeur du champ.J'utilise cette technique dans un mappeur générique ResultSet-to-and-from-model.
la source