Получите доступ к Вложенному полю, используя Java Отражение - PullRequest
0 голосов
/ 06 января 2020

Предположим, у меня есть несколько классов в этом стиле:

public class A {
     public B element;
}

public class B {
     public C anotherElement; // where C refers to another type which contains types D, E, F, etc.....
}

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

    Field[] myFields = providedObject.getClass().getDeclaredFields();
    for (Field myField : myFields) {
        // do something here?? to access the sub-fields of the class
        // if I print out myField.getName(), I get the element of class A, but I also want to access the anotherElement of class B (without hard-coding the name 'anotherElement', I want a full traversal of all nested fields)
    }

На шаге «сделать что-то здесь» я хочу получить доступ к подполям myField, но я ничего не вижу в API поля это напрямую позволяет мне сделать это. Я попытался:

myField.getDeclaringClass (). GetDeclaredFields () -> это, кажется, возвращает тот же элемент, который мы уже видели, а не подэлементы

и

myField.getClass (). GetDeclaredFields () -> это, кажется, возвращает поля класса 'Field', а не моего класса A или B

Так как бы я мог получить доступ к вложенным полям из API-интерфейса отражения ?

Спасибо.

Ответы [ 2 ]

0 голосов
/ 06 января 2020

Это всего лишь рекурсия:

public static void traverseDepthFirst(Object obj) { // May need throws/catch!
    if (obj == null) {
        // ... do something for null ...
        return;
    }
    // ... perhaps do something different for arrays, primitives, String, etc.
    for (Field field : obj.getClass().getDeclaredFields()) {
        field.setAccessible(true);
        // ... pre-traversal code ...
        traverseDepthFirst(field.get(obj));
        // ... post-traversal code ...
    }
}

Редактировать: Это будет учитывать только листовой класс. Чтобы включить супер классы.

public static void traverseDepthFirst(Object obj) { // May need throws/catch!
    if (obj == null) {
        // ... do something for null ...
        return;
    }
    // ... perhaps do something different for arrays, primitives, String, etc.
    for (
        Class<?> clazz = obj.getClass();
        clazz != null;
        clazz = clazz.getSuperclass()
    ) {
        for (Field field : clazz.getDeclaredFields()) {
            field.setAccessible(true);
            // ... pre-traversal code ...
            traverseDepthFirst(field.get(obj));
            // ... post-traversal code ...
        }
    }
}
0 голосов
/ 06 января 2020

Я добавил следующее утверждение, чтобы выйти из рекурсивного метода. Вы можете изменить это как хотите.

        if (clazz == null || clazz.isPrimitive() || !clazz.getPackage().getName().startsWith("com.vvv.stack02")) {
            return;
        }

Основная идея заключается в том, что вам нужно преобразовать поле в класс, набрав следующую строку.

Class<?> fieldClass = myField.getType();

public class Main {

    public static void main(String[] args) {
        printFields(A.class);
    }

    public static void printFields(Class<?> clazz) {

        if (clazz == null || clazz.isPrimitive() || !clazz.getPackage().getName().startsWith("com.vvv.stack02")) {
            return;
        }

        Field[] myFields = clazz.getDeclaredFields();
        for (Field myField : myFields) {
            System.out.println(clazz.getSimpleName() + "->" + myField.getType().getSimpleName() + ":" + myField.getName());
            Class<?> fieldClass = myField.getType();
            printField(fieldClass);
        }

    }

    public static class A {
        public B element;
    }

    public static class B {
        public C anotherElement; // where C refers to another type which contains types D, E, F, etc.....
    }

    public static class C {
        public Integer a;
    }

}
...