154 votes

Récupération des noms/valeurs des attributs hérités à l'aide de Java Reflection

J'ai un objet Java 'ChildObj' qui est étendu à partir de 'ParentObj'. Maintenant, s'il est possible de récupérer tous les noms et valeurs des attributs de ChildObj, y compris les attributs hérités, en utilisant le mécanisme de réflexion Java ?

[Classe.getFields](http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Class.html#getFields()) me donne le tableau des attributs publics, et [Classe.getDeclaredFields](http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Class.html#getDeclaredFields()) me donne le tableau de tous les champs, mais aucun d'entre eux n'inclut la liste des champs hérités.

Existe-t-il un moyen de récupérer également les attributs hérités ?

206voto

dfa Points 54490

Non, vous devez l'écrire vous-même. Il s'agit d'une simple méthode récursive appelée sur [Class.getSuperClass()](http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Class.html#getSuperclass()) :

public static List<Field> getAllFields(List<Field> fields, Class<?> type) {
    fields.addAll(Arrays.asList(type.getDeclaredFields()));

    if (type.getSuperclass() != null) {
        getAllFields(fields, type.getSuperclass());
    }

    return fields;
}

@Test
public void getLinkedListFields() {
    System.out.println(getAllFields(new LinkedList<Field>(), LinkedList.class));
}

7 votes

Passer un argument mutable et le retourner n'est probablement pas une bonne conception. fields.addAll(type.getDeclaredFields()) ; serait plus conventionnel qu'une boucle for améliorée avec add.

0 votes

Je ressentirais le besoin de le compiler au moins (sur stackoverflow !), et probablement d'ajouter un peu de Arrays.asList.

0 votes

Il semble que votre code recueille tous les champs, y compris les champs privés et statiques qui ne sont pas hérités.

99voto

Esko Luontola Points 53877
    public static List<Field> getAllFields(Class<?> type) {
        List<Field> fields = new ArrayList<Field>();
        for (Class<?> c = type; c != null; c = c.getSuperclass()) {
            fields.addAll(Arrays.asList(c.getDeclaredFields()));
        }
        return fields;
    }

10 votes

C'est la solution que je préfère, mais je l'appellerais "getAllFields" car elle renvoie également les champs de la classe donnée.

4 votes

Bien que j'aime beaucoup la récursivité (c'est amusant !), je préfère la lisibilité de cette méthode et les paramètres plus intuitifs (pas besoin de passer une nouvelle collection), plus de if (implicite dans la clause for) et pas d'itération sur les champs eux-mêmes.

0 votes

Il montre récursif est inutile et J'aime les codes courts ! thx ! :)

41voto

Chris Points 4263

Si, au contraire, vous vouliez vous appuyer sur une bibliothèque pour accomplir cette tâche, Langage Apache Commons La version 3.2+ fournit FieldUtils.getAllFieldsList :

import java.lang.reflect.Field;
import java.util.AbstractCollection;
import java.util.AbstractList;
import java.util.AbstractSequentialList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.lang3.reflect.FieldUtils;
import org.junit.Assert;
import org.junit.Test;

public class FieldUtilsTest {

    @Test
    public void testGetAllFieldsList() {

        // Get all fields in this class and all of its parents
        final List<Field> allFields = FieldUtils.getAllFieldsList(LinkedList.class);

        // Get the fields form each individual class in the type's hierarchy
        final List<Field> allFieldsClass = Arrays.asList(LinkedList.class.getFields());
        final List<Field> allFieldsParent = Arrays.asList(AbstractSequentialList.class.getFields());
        final List<Field> allFieldsParentsParent = Arrays.asList(AbstractList.class.getFields());
        final List<Field> allFieldsParentsParentsParent = Arrays.asList(AbstractCollection.class.getFields());

        // Test that `getAllFieldsList` did truly get all of the fields of the the class and all its parents 
        Assert.assertTrue(allFields.containsAll(allFieldsClass));
        Assert.assertTrue(allFields.containsAll(allFieldsParent));
        Assert.assertTrue(allFields.containsAll(allFieldsParentsParent));
        Assert.assertTrue(allFields.containsAll(allFieldsParentsParentsParent));
    }
}

9voto

Nick Holt Points 12945

Vous devez appeler :

Class.getSuperclass().getDeclaredFields()

En remontant la hiérarchie de l'héritage si nécessaire.

2voto

Theo Platt Points 21
private static void addDeclaredAndInheritedFields(Class<?> c, Collection<Field> fields) {
    fields.addAll(Arrays.asList(c.getDeclaredFields())); 
    Class<?> superClass = c.getSuperclass(); 
    if (superClass != null) { 
        addDeclaredAndInheritedFields(superClass, fields); 
    }       
}

Version fonctionnelle de la solution "DidYouMeanThatTomHa..." ci-dessus

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