Получение названий/значений наследуемых атрибутов с использованием Java Reflection
У меня есть объект Java "ChildObj", который расширен с "ParentObj". Теперь, если можно получить все имена атрибутов и значения ChildObj, включая также унаследованные атрибуты, используя механизм отражения Java?
Class.getFields дает мне массив открытых атрибутов и Class.getDeclaredFields дает мне массив всех полей, но ни один из них не содержит список унаследованных полей.
Есть ли способ получить унаследованные атрибуты?
Ответы
Ответ 1
нет, вам нужно написать это самостоятельно. Это простой рекурсивный метод, называемый 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));
}
Ответ 2
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;
}
Ответ 3
Если вместо этого вы хотели полагаться на библиотеку, чтобы выполнить это, 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 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));
}
}
Ответ 4
Вам нужно позвонить:
Class.getSuperclass().getDeclaredFields()
Повторно пересматривая иерархию наследования.
Ответ 5
Использование библиотеки Reflections:
public Set<Field> getAllFields(Class<?> aClass) {
return org.reflections.ReflectionUtils.getAllFields(aClass);
}
Ответ 6
Рекурсивные решения в порядке, единственная небольшая проблема заключается в том, что они возвращают надмножество объявленных и унаследованных членов. Обратите внимание, что метод getDeclaredFields() возвращает также частные методы. Поэтому, учитывая, что вы перемещаете всю иерархию суперкласса, вы будете включать все частные поля, объявленные в суперклассах, и те, которые не наследуются.
Простой фильтр с модификатором .isPublic || Модификатор. Защищенный предикат:
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);
}
}
Ответ 7
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..." выше
Ответ 8
Вы можете попробовать:
Class parentClass = getClass().getSuperclass();
if (parentClass != null) {
parentClass.getDeclaredFields();
}
Ответ 9
Короче и с меньшим экземпляром объекта? ^^
private static Field[] getAllFields(Class<?> type) {
if (type.getSuperclass() != null) {
return (Field[]) ArrayUtils.addAll(getAllFields(type.getSuperclass()), type.getDeclaredFields());
}
return type.getDeclaredFields();
}
Ответ 10
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);
}
}
Ответ 11
Это переформулировка принятого ответа от @user1079877. Это может быть версия, которая не изменяет параметр функции, а также использует некоторые современные функции Java.
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);
}
}
Эта реализация также делает вызов немного более кратким:
var fields = getFields(MyType.class);
Ответ 12
Я недавно видел этот код из 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;
}