118

I found a way to get inherited members via class.getDeclaredFields(); and acces to private members via class.getFields() But i'm looking for private inherited fields. How can i achieve this?

Andreas Fester
  • 36,091
  • 7
  • 95
  • 123
benzen
  • 6,204
  • 4
  • 25
  • 37
  • 28
    "private inherited fields" does not exist. If a field is private, it is not inherited, and remains only to the scope of the parent class. To access parent private fields, you have to access parent class first (cf. aioobe's response) – Benoit Courtine Aug 25 '10 at 15:22
  • 6
    that said, protected fields are inherited, but you have to do the same to get them by reflection. – Bozho Aug 25 '10 at 16:14
  • Possible duplicate of [Retrieving the inherited attribute names/values using Java Reflection](https://stackoverflow.com/questions/1042798/retrieving-the-inherited-attribute-names-values-using-java-reflection) – Vadzim May 28 '19 at 13:04

8 Answers8

138

This should demonstrate how to solve it:

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 f = b.getClass().getSuperclass().getDeclaredField("i");
        f.setAccessible(true);
        System.out.println(f.get(b));
    }
}

(Or Class.getDeclaredFields for an array of all fields.)

Output:

5
aioobe
  • 413,195
  • 112
  • 811
  • 826
  • Does this get all superclasses' fields or just the direct superclass? – NeoZoom.lua May 14 '19 at 16:28
  • Direct super classes' fields. You can recurse on `getSuperclass()` until you reach `null` if you want to go higher. – aioobe May 14 '19 at 17:11
  • Why don't you use `getDeclaredFields()[0]` or `getDeclaredField("i")` but rather repeat the `[0]` array access in the next two statements? – Holger Dec 03 '19 at 15:41
  • It's due to the way this particular question is formulated. It was basically just a demonstration of how to use `getDeclaredFields`. Answer has been updated. – aioobe Dec 03 '19 at 15:47
47

The best approach here is using the Visitor Pattern do find all fields in the class and all super classes and execute a callback action on them.


Implementation

Spring has a nice Utility class ReflectionUtils that does just that: it defines a method to loop over all fields of all super classes with a callback: ReflectionUtils.doWithFields()

Documentation:

Invoke the given callback on all fields in the target class, going up the class hierarchy to get all declared fields.

Parameters:
- clazz - the target class to analyze
- fc - the callback to invoke for each field
- ff - the filter that determines the fields to apply the callback to

Sample code:

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

Output:

Found field private transient boolean javax.management.relation.RoleUnresolvedList.typeSafe in type class javax.management.relation.RoleUnresolvedList
Found field private transient boolean javax.management.relation.RoleUnresolvedList.tainted in type class javax.management.relation.RoleUnresolvedList
Found field private transient java.lang.Object[] java.util.ArrayList.elementData in type class java.util.ArrayList
Found field private int java.util.ArrayList.size in type class java.util.ArrayList
Found field protected transient int java.util.AbstractList.modCount in type class java.util.AbstractList

Felk
  • 7,720
  • 2
  • 35
  • 65
Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
  • 3
    that is not a "visitor pattern", but it is still a very nice tool if you have the Spring virus in your code. thanks for sharing it :) – thinlizzy Aug 28 '13 at 00:27
  • 3
    @jose.diego I'm pretty sure you could argue about that. It visits a class hierarchy rather than an object tree, but the principle remains the same – Sean Patrick Floyd Aug 28 '13 at 14:43
  • Not sure if this comment will get a response, but you're only visiting a particular field at a time with this solution. If I need to look at other fields at the same time -- e.g., set this field to "abc" if another field is NULL -- I don't have the object as a whole available to me. – gene b. Nov 25 '16 at 19:25
  • Its too bad that the JavaDoc for this class indicates that "it is only intended for internal use", so this is a possible risk to anyone who wishes to use it. – spaceman spiff Jul 09 '18 at 04:07
  • 1
    @spacemanspiff you're technically correct, but this class has been around for about 15 years (including 4 major release versions) and has widely been used by many Spring customers. I doubt they'll pull it back now. – Sean Patrick Floyd Jul 09 '18 at 16:31
37

This'll do it:

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

If you use a code coverage tool like EclEmma, you have to watch out: they add a hidden field to each of your classes. In the case of EclEmma, these fields are marked synthetic, and you can filter them out like this:

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;
}
jqno
  • 15,133
  • 7
  • 57
  • 84
21
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);
}

(based on this answer)

Community
  • 1
  • 1
Exterminator13
  • 2,152
  • 1
  • 23
  • 28
16

In fact i use a complex type hierachy so you solution is not complete. I need to make a recursive call to get all the private inherited fields. Here is my solution

 /**
 * Return the set of fields declared at all level of class hierachy
 */
public static List<Field> getAllFields(Class<?> clazz) {
    return getAllFieldsRec(clazz, new ArrayList<>());
}

private static List<Field> getAllFieldsRec(Class<?> clazz, List<Field> list) {
    Class<?> superClazz = clazz.getSuperclass();
    if (superClazz != null) {
        getAllFieldsRec(superClazz, list);
    }
    list.addAll(Arrays.asList(clazz.getDeclaredFields()));
    return list;
}
Lii
  • 11,553
  • 8
  • 64
  • 88
benzen
  • 6,204
  • 4
  • 25
  • 37
  • However, his solution did get you on the right path, didn't it? – aperkins Aug 25 '10 at 15:55
  • 1
    Vector is bad old code. Please use a current data structure from the collections framework (ArrayList is adequate in most cases) – Sean Patrick Floyd Aug 25 '10 at 15:58
  • @aperkins the answer of aioobe look like mine, but i found it and then i saw the answer. @seanizer Vector is not that old, and it'a a member of the collection API – benzen Aug 25 '10 at 17:53
  • "As of the Java 2 platform v1.2, this class has been retrofitted to implement List, so that it becomes a part of Java's collection framework." retrofitted in 1.2? if that's not old then what is? Source: http://download.oracle.com/javase/1.4.2/docs/api/java/util/Vector.html – Sean Patrick Floyd Aug 25 '10 at 19:04
  • 8
    Vector has a huge overhead because everything is synchronized. And where you need synchronization, there are better classes in java.util.concurrent. Vector, Hashtable and StringBuffer should in most cases be replaced by ArrayList, HashMap and StringBuilder – Sean Patrick Floyd Aug 25 '10 at 19:09
8

I needed to add support for inherited fields for blueprints in Model Citizen. I derived this method that is a bit more concise for retrieving a Class' fields + inherited fields.

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;
}
mguymon
  • 8,946
  • 2
  • 39
  • 61
8
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);
}
palacsint
  • 28,416
  • 10
  • 82
  • 109
Kenny Cason
  • 12,109
  • 11
  • 47
  • 72
-1

Commons Lang has the util method FieldUtils#getAllFieldsList for this.

Lii
  • 11,553
  • 8
  • 64
  • 88