2009-06-25 14 views
91

Tengo un objeto Java 'ChildObj' que se extiende desde 'ParentObj'. Ahora, si es posible recuperar todos los nombres de atributos y valores de ChildObj, incluidos los atributos heredados también, utilizando el mecanismo de reflexión de Java?Recuperando los nombres/valores heredados de los atributos usando Java Reflection

Class.getFields me da la matriz de atributos públicos, y Class.getDeclaredFields me da la matriz de todos los campos, pero ninguno de ellos incluye la lista de campos heredados.

¿Hay alguna forma de recuperar los atributos heredados también?

Respuesta

132

no, tiene que escribirlo usted mismo. Es un método simple llamada recursiva en Class.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)); 
} 
+1

sí. pensado en eso. pero quería verificar si hay alguna otra forma de hacerlo. Gracias. :) – Veera

+0

funcionó. Gracias. – Veera

+6

Pasar un argumento mutable y devolverlo probablemente no sea un gran diseño. fields.addAll (type.getDeclaredFields()); sería más convencional que un bucle for mejorado con add. –

5

Es necesario llamar:

Class.getSuperclass().getDeclaredFields() 

manera recursiva hasta la jerarquía de herencia, según sea necesario.

1

que puede probar:

Class parentClass = getClass().getSuperclass(); 
    if (parentClass != null) { 
     parentClass.getDeclaredFields(); 
    } 
0
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); 
    } 
} 
71
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; 
    } 
+9

Esta es mi solución preferida, sin embargo, la llamaría "getAllFields" porque también devuelve los campos de la clase especificada. – Pino

+0

Estoy de acuerdo con Pino – Marquez

+3

Aunque me gusta mucho la recursividad (¡es divertido!), Prefiero la legibilidad de este método y los parámetros más intuitivos (no es necesario que se pase una nueva colección), no más si (implícito en la cláusula for) y ninguna iteración sobre los campos mismos. –

2
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); 
    }  
} 

versión de "DidYouMeanThatTomHa ..." solución anterior

3

Las soluciones recursivas están bien de trabajo, el único problema es que devuelvan un superconjunto de miembros declarados y heredados. Tenga en cuenta que el método getDeclaredFields() devuelve también métodos privados. Por lo tanto, dado que navega por toda la jerarquía de superclase, incluirá todos los campos privados declarados en las superclases, y no se heredarán.

Un filtro simple con un Modificador.isPublic || predicado Modifier.isProtected haría:

import static java.lang.reflect.Modifier.isPublic; 
import static java.lang.reflect.Modifier.isProtected; 

(...) 

List<Field> inheritableFields = new ArrayList<Field>(); 
for (Field field : type.getDeclaredFields()) { 
    if (isProtected(field.getModifiers()) || isPublic(field.getModifiers())) { 
     inheritableFields.add(field); 
    } 
} 
25

Si por el contrario usted quiere depender de una biblioteca de lograr esto, Apache Commons Lang versión 3.2+ ofrece 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)); 
    } 
} 
+3

Boom! Me encanta no reinventar la rueda. Saludos por esto. –

0

más corto y con menos objeto instanciado? ^^

private static Field[] getAllFields(Class<?> type) { 
    if (type.getSuperclass() != null) { 
     return (Field[]) ArrayUtils.addAll(getAllFields(type.getSuperclass()), type.getDeclaredFields()); 
    } 
    return type.getDeclaredFields(); 
} 
+0

HI @Alexis LEGROS: ArrayUtils no puede encontrar el símbolo. –

+1

Esta clase es de Apache Commons Lang. –

+0

Apache ya tiene una función FieldUtils.getAllFields para manejar esta solicitud de pregunta. –

4

Use Reflexiones de biblioteca:

public Set<Field> getAllFields(Class<?> aClass) { 
    return org.reflections.ReflectionUtils.getAllFields(aClass); 
} 
Cuestiones relacionadas