programing

Java Reflection을 사용하여 상속된 속성 이름/값 검색

goodjava 2022. 11. 5. 17:47

Java Reflection을 사용하여 상속된 속성 이름/값 검색

자바 오브젝트 ChildObj는 ParentObj에서 확장되어 있습니다.Java 리플렉션메커니즘을 사용하여 상속된 속성을 포함하여 ChildObj의 모든 속성 이름과 값을 가져올 수 있습니까?

Class.getFields는 퍼블릭애트리뷰트의 배열을 나타내고 Class.getDeclaredFields는 모든 필드의 배열을 나타내지만 상속된 필드 목록을 포함하는 필드는 없습니다.

상속된 Atribute를 취득할 수 있는 방법이 있습니까?

아니요, 직접 쓰셔야 해요.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));
}
    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;
    }

대신 라이브러리를 사용하여 이 작업을 수행할 경우 Apache Commons Lang 버전 3.2+는 다음을 제공합니다.

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

문의처:

Class.getSuperclass().getDeclaredFields()

필요에 따라 상속 계층을 재귀업합니다.

반사 라이브러리 사용:

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

getFields(): 클래스 계층 전체의 모든 퍼블릭필드를 가져오고
getDeclaredFields(): 수식자에 관계없이 현재 클래스에 대해서만 모든 필드를 가져옵니다.따라서 관련된 모든 계층에 대해 이해해야 합니다.
저는 최근에 org.apache.commons.lang3.reflect에서 이 코드를 보았습니다.필드 유틸리티

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

재귀적 솔루션은 정상입니다.단, 선언된 멤버와 상속된 멤버의 슈퍼셋을 반환하는 것이 유일한 작은 문제입니다.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);
    }
}

spring util 라이브러리를 사용하면 를 사용하여 클래스에 특정 Atribut이1개 존재하는지 여부를 확인할 수 있습니다.

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

log.info(field2.getName());

API 문서:
https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/util/ReflectionUtils.html

또는

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

 log.info(field2.getName());

API 문서:
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/util/ReflectionUtils.html

@parames(@parames)

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

"Did You Mean That Tom Ha" 작업 버전..위의 솔루션

다음 작업을 수행할 수 있습니다.

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

인스턴스화된 개체 수가 적고 더 짧습니까? ^^

private static Field[] getAllFields(Class<?> type) {
    if (type.getSuperclass() != null) {
        return (Field[]) ArrayUtils.addAll(getAllFields(type.getSuperclass()), type.getDeclaredFields());
    }
    return type.getDeclaredFields();
}
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);
    }
}

이것은 @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);

FieldUtils에 의해 처리되지 않은 몇 가지 기호가 있습니다.특히 합성 필드(JaCoCo에 의해 삽입됨)와 열거형에는 각 인스턴스에 대한 필드가 있습니다.또한 오브젝트 그래프를 통과하여 모든 필드를 가져오고 각 필드의 필드를 가져오면 무한 루프 상태가 됩니다.암탉이 열거형을 쳤군요확장 솔루션은 다음과 같습니다(솔직히 말씀드리면, 이것은 어딘가에 있는 도서관에 보관되어 있을 것입니다).

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

스팍 테스트 클래스(Groovy는 합성 필드를 추가합니다):

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

    }
}

언급URL : https://stackoverflow.com/questions/1042798/retrieving-the-inherited-attribute-names-values-using-java-reflection