164

I've a Java object 'ChildObj' which is extended from 'ParentObj'. Now, if it is possible to retrieve all the attribute names and values of ChildObj, including the inherited attributes too, using Java reflection mechanism?

Class.getFields gives me the array of public attributes, and Class.getDeclaredFields gives me the array of all fields, but none of them includes the inherited fields list.

Is there any way to retrieve the inherited attributes also?

Veera
  • 32,532
  • 36
  • 98
  • 137

15 Answers15

220

no, you need to write it yourself. It is a simple recursive method called on 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));
}
user1079877
  • 9,008
  • 4
  • 43
  • 54
dfa
  • 114,442
  • 31
  • 189
  • 228
101
    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;
    }
Esko Luontola
  • 73,184
  • 17
  • 117
  • 128
  • 4
    Although I like very much recursivity (it's fun!), I prefer the readability of this method and the more intuitive parameters (not required a new collection to be pass), no more if (implicit in the for clause) and no iteration over fields themselves. – Remi Morin Sep 10 '13 at 13:22
  • it shows recursive is unnecessary and.. I like short codes! thx! :) – Aquarius Power Mar 04 '15 at 08:08
  • In many years i always think the initial value in for is just an integer, with @Veera's question I think only recursive can solve it,@Esko Luontola your command is awesome. – Touya Akira Sep 09 '17 at 10:20
45

If instead you wanted to rely upon a library to accomplish this, Apache Commons Lang version 3.2+ provides 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));
    }
}
Chris
  • 6,761
  • 6
  • 52
  • 67
9

You need to call:

Class.getSuperclass().getDeclaredFields()

Recursing up the inheritance hierarchy as necessary.

Burkhard
  • 14,596
  • 22
  • 87
  • 108
Nick Holt
  • 33,455
  • 4
  • 52
  • 58
5

Use Reflections library:

public Set<Field> getAllFields(Class<?> aClass) {
    return org.reflections.ReflectionUtils.getAllFields(aClass);
}
Lukasz Ochmanski
  • 970
  • 1
  • 11
  • 15
5

getFields(): Gets all the public fields up the entire class hierarchy and
getDeclaredFields(): Gets all the fields, regardless of their modifiers but only for the current class. So, you have to get for all the hierarchy involved.
I recently saw this code from org.apache.commons.lang3.reflect.FieldUtils

public static List<Field> getAllFieldsList(final Class<?> cls) {
        Validate.isTrue(cls != null, "The class must not be null");
        final List<Field> allFields = new ArrayList<>();
        Class<?> currentClass = cls;
        while (currentClass != null) {
            final Field[] declaredFields = currentClass.getDeclaredFields();
            Collections.addAll(allFields, declaredFields);
            currentClass = currentClass.getSuperclass();
        }
        return allFields;
}
Aman
  • 1,627
  • 13
  • 19
  • 1
    Its better than best answer, because while cycle always faster than recursive calls. But i think LinkedList as data structure more suitable instead of ArrayList, because ArraysList will be resized (a few times), when size of list reaches capacity value, what will entail time costs – Alex Mar 03 '21 at 11:15
4

With spring util library, you can use to check if one specific attribute exists into class:

Field field = ReflectionUtils.findRequiredField(YOUR_CLASS.class, "ATTRIBUTE_NAME");

log.info(field2.getName());

Api doc:
https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/util/ReflectionUtils.html

or

 Field field2 = ReflectionUtils.findField(YOUR_CLASS.class, "ATTRIBUTE_NAME");

 log.info(field2.getName());

Api doc:
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/util/ReflectionUtils.html

@cheers

4

The recursive solutions are OK, the only small issue is that they return a superset of declared and inherited members. Note that getDeclaredFields() method returns also private methods. So given that you navigate the whole superclass hierarchy you will include all private fields declared in the superclasses, and those don't get inherited.

A simple filter with a Modifier.isPublic || Modifier.isProtected predicate would do:

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);
    }
}
Marek Dec
  • 954
  • 6
  • 8
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); 
    }       
}

Working version of "DidYouMeanThatTomHa..." solution above

Theo Platt
  • 21
  • 1
1

You can try:

   Class parentClass = getClass().getSuperclass();
   if (parentClass != null) {
      parentClass.getDeclaredFields();
   }
Manuel Selva
  • 18,554
  • 22
  • 89
  • 134
1

Shorter and with less object instantiated ? ^^

private static Field[] getAllFields(Class<?> type) {
    if (type.getSuperclass() != null) {
        return (Field[]) ArrayUtils.addAll(getAllFields(type.getSuperclass()), type.getDeclaredFields());
    }
    return type.getDeclaredFields();
}
Alexis LEGROS
  • 539
  • 10
  • 14
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);
    }
}
codewandler
  • 536
  • 6
  • 9
0

This is a rewording of the accepted answer by @user1079877. It might that a version which does not modify a parameter of the function and also uses some modern Java features.

public <T> Field[] getFields(final Class<T> type, final Field... fields) {
    final Field[] items = Stream.of(type.getDeclaredFields(), fields).flatMap(Stream::of).toArray(Field[]::new);
    if (type.getSuperclass() == null) {
        return items;
    } else {
        return getFields(type.getSuperclass(), items);
    }
}

This implementation also makes invocation a bit more concise:

var fields = getFields(MyType.class);
scrutari
  • 1,378
  • 2
  • 17
  • 33
0

There are a couple of quirks that aren't addressed by FieldUtils - specifically synthetic fields (eg injected by JaCoCo) and also the fact that an enum type of course has a field for each instance, and if you are traversing an object graph, getting all fields and then getting the fields of each of them etc, then you will get into an infinite loop when you hit an enum. An extended solution (and to be honest I'm sure this must live in a library somewhere!) would be:

/**
 * Return a list containing all declared fields and all inherited fields for the given input
 * (but avoiding any quirky enum fields and tool injected fields).
 */
public List<Field> getAllFields(Object input) {
    return getFieldsAndInheritedFields(new ArrayList<>(), input.getClass());
}

private List<Field> getFieldsAndInheritedFields(List<Field> fields, Class<?> inputType) {
    fields.addAll(getFilteredDeclaredFields(inputType));
    return inputType.getSuperclass() == null ? fields : getFieldsAndInheritedFields(fields, inputType.getSuperclass());

}

/**
 * Where the input is NOT an {@link Enum} type then get all declared fields except synthetic fields (ie instrumented
 * additional fields). Where the input IS an {@link Enum} type then also skip the fields that are all the
 * {@link Enum} instances as this would lead to an infinite loop if the user of this class is traversing
 * an object graph.
 */
private List<Field> getFilteredDeclaredFields(Class<?> inputType) {
    return Arrays.asList(inputType.getDeclaredFields()).stream()
                 .filter(field -> !isAnEnum(inputType) ||
                         (isAnEnum(inputType) && !isSameType(field, inputType)))
                 .filter(field -> !field.isSynthetic())
                 .collect(Collectors.toList());

}

private boolean isAnEnum(Class<?> type) {
    return Enum.class.isAssignableFrom(type);
}

private boolean isSameType(Field input, Class<?> ownerType) {
    return input.getType().equals(ownerType);
}

Test class in Spock (and Groovy adds synthetic fields):

class ReflectionUtilsSpec extends Specification {

    def "declared fields only"() {

        given: "an instance of a class that does not inherit any fields"
        def instance = new Superclass()

        when: "all fields are requested"
        def result = new ReflectionUtils().getAllFields(instance)

        then: "the fields declared by that instance's class are returned"
        result.size() == 1
        result.findAll { it.name in ['superThing'] }.size() == 1
    }


    def "inherited fields"() {

        given: "an instance of a class that inherits fields"
        def instance = new Subclass()

        when: "all fields are requested"
        def result = new ReflectionUtils().getAllFields(instance)

        then: "the fields declared by that instance's class and its superclasses are returned"
        result.size() == 2
        result.findAll { it.name in ['subThing', 'superThing'] }.size() == 2

    }

    def "no fields"() {
        given: "an instance of a class with no declared or inherited fields"
        def instance = new SuperDooperclass()

        when: "all fields are requested"
        def result = new ReflectionUtils().getAllFields(instance)

        then: "the fields declared by that instance's class and its superclasses are returned"
        result.size() == 0
    }

    def "enum"() {

        given: "an instance of an enum"
        def instance = Item.BIT

        when: "all fields are requested"
        def result = new ReflectionUtils().getAllFields(instance)

        then: "the fields declared by that instance's class and its superclasses are returned"
        result.size() == 3
        result.findAll { it.name == 'smallerItem' }.size() == 1
    }

    private class SuperDooperclass {
    }

    private class Superclass extends SuperDooperclass {
        private String superThing
    }


    private class Subclass extends Superclass {
        private String subThing
    }

    private enum Item {

        BIT("quark"), BOB("muon")

        Item(String smallerItem) {
            this.smallerItem = smallerItem
        }

        private String smallerItem

    }
}
Chris
  • 1,644
  • 1
  • 11
  • 15
0

I know this is a long overdue answer, but I just put here my answer just for my reference or anyone who is interested about an implementation without reflection as an extension of @dfa's answer;

public List<Field> getDeclaredFields(Class<?> tClass) {
    List<Field> fields = new LinkedList<>();

    while (tClass != null) {
        fields.addAll(Arrays.asList(tClass.getDeclaredFields()));
        tClass = tClass.getSuperclass();
    }

    return fields;
}
Sachith Dickwella
  • 1,388
  • 2
  • 14
  • 22