Access to private inherited fields via reflection in Java

99,189

Solution 1

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

Solution 2

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

Solution 3

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

Solution 4

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

Solution 5

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)

Share:
99,189

Related videos on Youtube

benzen
Author by

benzen

Analyst programer

Updated on July 08, 2022

Comments

  • benzen
    benzen almost 2 years

    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?

    • Benoit Courtine
      Benoit Courtine almost 14 years
      "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)
    • Bozho
      Bozho almost 14 years
      that said, protected fields are inherited, but you have to do the same to get them by reflection.
    • Vadzim
      Vadzim about 5 years
  • aperkins
    aperkins almost 14 years
    However, his solution did get you on the right path, didn't it?
  • Sean Patrick Floyd
    Sean Patrick Floyd almost 14 years
    Vector is bad old code. Please use a current data structure from the collections framework (ArrayList is adequate in most cases)
  • benzen
    benzen almost 14 years
    @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
  • Sean Patrick Floyd
    Sean Patrick Floyd almost 14 years
    "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: download.oracle.com/javase/1.4.2/docs/api/java/util/Vector.h‌​tml
  • Sean Patrick Floyd
    Sean Patrick Floyd almost 14 years
    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
  • Anatoliy
    Anatoliy about 12 years
    Thanks for your remark about synthetic fields, EMMA does the same.
  • Peter Hawkins
    Peter Hawkins over 11 years
    this gets declared and inherited fields of the argument class so should be named getDeclaredAndInheritedPrivateFields. perfect though thanks!
  • thinlizzy
    thinlizzy almost 11 years
    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 :)
  • Sean Patrick Floyd
    Sean Patrick Floyd almost 11 years
    @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
  • Lucas Crawford
    Lucas Crawford over 8 years
    nice catch on the isSynthetic :)
  • gene b.
    gene b. over 7 years
    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.
  • spaceman spiff
    spaceman spiff almost 6 years
    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.
  • Sean Patrick Floyd
    Sean Patrick Floyd almost 6 years
    @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.
  • VimNing
    VimNing about 5 years
    Does this get all superclasses' fields or just the direct superclass?
  • aioobe
    aioobe about 5 years
    Direct super classes' fields. You can recurse on getSuperclass() until you reach null if you want to go higher.
  • VimNing
    VimNing about 5 years
    Thanks for superb answer~
  • Holger
    Holger over 4 years
    Why don't you use getDeclaredFields()[0] or getDeclaredField("i") but rather repeat the [0] array access in the next two statements?
  • aioobe
    aioobe over 4 years
    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.