views:

249

answers:

5

I founded 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?

+5  A: 

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[] fs = b.getClass().getSuperclass().getDeclaredFields();
        fs[0].setAccessible(true);
        System.out.println(fs[0].get(b));
    }
}

Output:

5
aioobe
A: 

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;
}
BenZen
However, his solution did get you on the right path, didn't it?
aperkins
Vector is bad old code. Please use a current data structure from the collections framework (ArrayList is adequate in most cases)
seanizer
@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
"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
seanizer
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
seanizer
ok, i was wrong, thanks for pointing me this link.
BenZen
+3  A: 

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) {
        result.addAll(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
+1  A: 

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
seanizer
A: 
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);

}

KennyCason