Acceso a campos heredados privados mediante reflexión en Java


Encontré una manera de obtener miembros heredados a través de class.getDeclaredFields(); y acceso a los miembros privados a través de class.getFields() Pero estoy buscando campos privados heredados. ¿Cómo puedo lograr esto?

Author: Andreas Fester, 2010-08-25

7 answers

Esto debería demostrar cómo resolverlo:

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

Salida:

5
 114
Author: aioobe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-25 15:14:32

El mejor enfoque aquí es usar el Patrón de visitante encuentre todos los campos de la clase y todas las superclases y ejecute una acción de devolución de llamada en ellos.


Aplicación

La primavera tiene una buena clase de utilidad ReflectionUtils eso hace precisamente eso: define un método para recorrer todos los campos de todas las super clases con una devolución de llamada: ReflectionUtils.doWithFields()

Documentación:

Invoca la devolución de llamada dada en todos los campos de la clase de destino, subiendo el jerarquía de clases para obtener todos los campos declarados.

Parámetros:
- clazz-la clase objetivo a analizar
- fc-la devolución de llamada a invocar para cada campo
- ff-el filtro que determina los campos para aplicar la devolución de llamada a

Código de ejemplo:

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

Salida:

Se encontró el campo private transient boolean javax.gestión.relaci.RoleUnresolvedList.typeSafe en clase de tipo javax.gestión.relaci.RoleUnresolvedList
Encontrado campo privado transient boolean javax.gestión.relaci.RoleUnresolvedList.manchado en la clase de tipo javax.gestión.relaci.RoleUnresolvedList
Se ha encontrado el campo private transient java.lang.Objeto [] java.útil.ArrayList.elementData en clase de tipo java.útil.ArrayList
Encontrado campo privado en java.útil.ArrayList.tamaño en clase de tipo java.útil.ArrayList
Encontrado campo protegido transient int java.útil.AbstractList.modCount en escriba la clase java.útil.AbstractList

 37
Author: Sean Patrick Floyd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-18 16:12:18

Esto lo hará:

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 usas una herramienta de cobertura de código como EclEmma, tienes que tener cuidado: agregan un campo oculto a cada una de tus clases. En el caso de EclEmma, estos campos están marcados sintético , y puedes filtrarlos así:

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;
}
 29
Author: jqno,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-23 07:58:44
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);
}

(basado en esta respuesta)

 16
Author: Exterminator13,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:36

De hecho utilizo un tipo complejo hierachy por lo que la solución no está completa. Necesito hacer una llamada recursiva para obtener todos los campos heredados privados. Aquí está mi solución

 /**
 * 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;
}
 14
Author: benzen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-25 15:47:12
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);
}
 6
Author: Kenny Cason,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-20 01:27:48

Necesitaba agregar soporte para campos heredados para blueprints en Model Citizen. Derivé este método que es un poco más conciso para recuperar los campos + campos heredados de una clase.

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;
}
 6
Author: mguymon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-09 16:34:45