Получение имен / значений унаследованных атрибутов с использованием Java Reflection - PullRequest
112 голосов
/ 25 июня 2009

У меня есть Java-объект ChildObj, который расширен от ParentObj. Теперь, если возможно извлечь все имена и значения атрибутов ChildObj, включая унаследованные атрибуты, используя механизм отражения Java?

Class.getFields дает мне массив открытых атрибутов, а Class.getDeclaredFields дает мне массив всех полей, но ни одно из них не включает список унаследованных полей.

Есть ли способ также получить унаследованные атрибуты?

Ответы [ 12 ]

157 голосов
/ 25 июня 2009

нет, вам нужно написать это самостоятельно.Это простой рекурсивный метод, вызываемый 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));
}
80 голосов
/ 09 марта 2010
    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;
    }
33 голосов
/ 28 мая 2014

Если вместо этого вы хотите использовать библиотеку для достижения этой цели, Apache Commons Lang версии 3.2+ предоставляет 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));
    }
}
6 голосов
/ 25 июня 2009

Вам нужно позвонить:

Class.getSuperclass().getDeclaredFields()

При необходимости повторное использование иерархии наследования.

5 голосов
/ 10 июня 2016

Использовать библиотеку отражений:

public Set<Field> getAllFields(Class<?> aClass) {
    return org.reflections.ReflectionUtils.getAllFields(aClass);
}
3 голосов
/ 22 декабря 2011

Рекурсивные решения в порядке, единственная небольшая проблема заключается в том, что они возвращают расширенный набор объявленных и унаследованных членов. Обратите внимание, что метод getDeclaredFields () возвращает также закрытые методы. Поэтому, учитывая, что вы перемещаетесь по всей иерархии суперклассов, вы включаете все частные поля, объявленные в суперклассах, и они не наследуются.

Простой фильтр с Modifier.isPublic || Предикат Modifier.isProtected будет делать:

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);
    }
}
2 голосов
/ 18 февраля 2011
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); 
    }       
}

Рабочая версия решения "DidYouMeanThatTomHa ..." выше

1 голос
/ 07 мая 2015

короче и с меньшим количеством экземпляров объекта? ^^

private static Field[] getAllFields(Class<?> type) {
    if (type.getSuperclass() != null) {
        return (Field[]) ArrayUtils.addAll(getAllFields(type.getSuperclass()), type.getDeclaredFields());
    }
    return type.getDeclaredFields();
}
1 голос
/ 25 июня 2009

Вы можете попробовать:

   Class parentClass = getClass().getSuperclass();
   if (parentClass != null) {
      parentClass.getDeclaredFields();
   }
0 голосов
/ 02 февраля 2019

Я недавно видел этот код из 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;
}
...