Retrieving the inherited attribute names/values using Java Reflection

JavaReflectionIntrospection

Java Problem Overview


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?

Java Solutions


Solution 1 - Java

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

Solution 2 - Java

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

Solution 3 - Java

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

Solution 4 - Java

You need to call:

Class.getSuperclass().getDeclaredFields()

Recursing up the inheritance hierarchy as necessary.

Solution 5 - Java

Use Reflections library:

public Set<Field> getAllFields(Class<?> aClass) {
    return org.reflections.ReflectionUtils.getAllFields(aClass);
}

Solution 6 - Java

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

Solution 7 - Java

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

Solution 8 - Java

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

Solution 9 - Java

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

Solution 10 - Java

You can try:

   Class parentClass = getClass().getSuperclass();
   if (parentClass != null) {
	  parentClass.getDeclaredFields();
   }

Solution 11 - Java

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

Solution 12 - Java

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

Solution 13 - Java

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

Solution 14 - Java

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

    }
}

Solution 15 - Java

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionVeeraView Question on Stackoverflow
Solution 1 - JavadfaView Answer on Stackoverflow
Solution 2 - JavaEsko LuontolaView Answer on Stackoverflow
Solution 3 - JavaChrisView Answer on Stackoverflow
Solution 4 - JavaNick HoltView Answer on Stackoverflow
Solution 5 - JavaLukasz OchmanskiView Answer on Stackoverflow
Solution 6 - JavaAmanView Answer on Stackoverflow
Solution 7 - JavaMarek DecView Answer on Stackoverflow
Solution 8 - JavaMarcelo RebouçasView Answer on Stackoverflow
Solution 9 - JavaTheo PlattView Answer on Stackoverflow
Solution 10 - JavaManuel SelvaView Answer on Stackoverflow
Solution 11 - JavaAlexis LEGROSView Answer on Stackoverflow
Solution 12 - JavaDidYouMeanThatTomHawtinView Answer on Stackoverflow
Solution 13 - JavascrutariView Answer on Stackoverflow
Solution 14 - JavaChrisView Answer on Stackoverflow
Solution 15 - JavaSachith DickwellaView Answer on Stackoverflow