J'ai trouvé un moyen d'obtenir des membres hérités via class.getDeclaredFields();
et d'accéder aux membres privés via class.getFields()
, mais je recherche des champs hérités privés. Comment puis-je atteindre cet objectif?
En fait, j'utilise une hiérarchie de types complexes, de sorte que votre solution n'est pas complète. Je dois faire un appel récursif pour obtenir tous les champs hérités privés. Voici ma solution
/**
* Return the set of fields declared at all level of class hierachy
*/
public Vector<Field> getAllFields(Class clazz) {
return getAllFieldsRec(clazz, new Vector<Field>());
}
private Vector<Field> getAllFieldsRec(Class clazz, Vector<Field> vector) {
Class superClazz = clazz.getSuperclass();
if(superClazz != null){
getAllFieldsRec(superClazz, vector);
}
vector.addAll(toVector(clazz.getDeclaredFields()));
return vector;
}
Cela devrait montrer comment le résoudre:
import Java.lang.reflect.Field;
class Super {
private int i = 5;
}
public class B extends Super {
public static void main(String[] args) throws Exception {
B b = new B();
Field[] fs = b.getClass().getSuperclass().getDeclaredFields();
fs[0].setAccessible(true);
System.out.println(fs[0].get(b));
}
}
Sortie:
5
La meilleure approche consiste ici à utiliser le Visitor Pattern trouve tous les champs de la classe et toutes les super classes et exécute une action de rappel sur eux.
Spring a une classe Nice Utility ReflectionUtils
qui ne fait que cela: elle définit une méthode pour boucler tous les champs de toutes les super classes avec un callback: ReflectionUtils.doWithFields()
Appelez le rappel donné sur tous les champs de la classe cible, en remontant la hiérarchie de la classe pour obtenir tous les champs déclarés.
Paramètres:
- clazz - la classe cible à analyser
- fc - le rappel à invoquer pour chaque champ
- ff - le filtre qui détermine les champs auxquels appliquer le rappel
ReflectionUtils.doWithFields(RoleUnresolvedList.class,
new FieldCallback(){
@Override
public void doWith(final Field field) throws IllegalArgumentException,
IllegalAccessException{
System.out.println("Found field " + field + " in type "
+ field.getDeclaringClass());
}
},
new FieldFilter(){
@Override
public boolean matches(final Field field){
final int modifiers = field.getModifiers();
// no static fields please
return !Modifier.isStatic(modifiers);
}
});
Champ trouvé privé transitoire booléen javax.management.relation.RoleUnresolvedList.typeSafe dans la classe type javax.management.relation.RoleUnresolvedList
Champ trouvé transitoire privé booléen javax.management.relation.RoleUnresolvedList.tainted dans la classe type javax.management.relation.RoleUnresolvedList
Champ trouvé transitoire privé Java.lang.Object [] Java.util.ArrayList.elementData dans la classe de type Java.util.ArrayList
Champ privé int trouvé dans Java.util.ArrayList.size dans la classe de type Java.util.ArrayList
Champ trouvé transitoire protégé int Java.util.AbstractList.modCount dans la classe type Java.util.AbstractList
Ça va le faire:
private List<Field> getInheritedPrivateFields(Class<?> type) {
List<Field> result = new ArrayList<Field>();
Class<?> i = type;
while (i != null && i != Object.class) {
Collections.addAll(result, i.getDeclaredFields());
i = i.getSuperclass();
}
return result;
}
Si vous utilisez un outil de couverture de code tel que EclEmma , vous devez faire attention: ils ajoutent un champ caché à chacune de vos classes. Dans le cas de EclEmma, ces champs sont marqués synthétiques , et vous pouvez les filtrer comme suit:
private List<Field> getInheritedPrivateFields(Class<?> type) {
List<Field> result = new ArrayList<Field>();
Class<?> i = type;
while (i != null && i != Object.class) {
for (Field field : i.getDeclaredFields()) {
if (!field.isSynthetic()) {
result.add(field);
}
}
i = i.getSuperclass();
}
return result;
}
public static Field getField(Class<?> clazz, String fieldName) {
Class<?> tmpClass = clazz;
do {
try {
Field f = tmpClass.getDeclaredField(fieldName);
return f;
} catch (NoSuchFieldException e) {
tmpClass = tmpClass.getSuperclass();
}
} while (tmpClass != null);
throw new RuntimeException("Field '" + fieldName
+ "' not found on class " + clazz);
}
(basé sur this réponse)
J'avais besoin d'ajouter un support pour les champs hérités pour les plans en Model Citizen . J'ai dérivé cette méthode qui est un peu plus concise pour récupérer les champs + les champs hérités d'une classe.
private List<Field> getAllFields(Class clazz) {
List<Field> fields = new ArrayList<Field>();
fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
Class superClazz = clazz.getSuperclass();
if(superClazz != null){
fields.addAll(getAllFields(superClazz));
}
return fields;
}
private static Field getField(Class<?> clazz, String fieldName) {
Class<?> tmpClass = clazz;
do {
for ( Field field : tmpClass.getDeclaredFields() ) {
String candidateName = field.getName();
if ( ! candidateName.equals(fieldName) ) {
continue;
}
field.setAccessible(true);
return field;
}
tmpClass = tmpClass.getSuperclass();
} while ( clazz != null );
throw new RuntimeException("Field '" + fieldName +
"' not found on class " + clazz);
}