Как обратиться к функционалу класса по имени класса переданного в строке String?

И так есть класс, в котором есть вложенные статичные классы, в которых лежат enum классы. Обращение к enum классу выглядит так: MainClass.Inner1.Enum2.getValueList(). Мне на вход метода приходит в виде строки String имена классов: Inner1, Enum2(например), после чего мне надо составить запрос указанный выше, чтобы получить список значений enum класса. По идее здесь речь идёт о Reflection, но сообразить как это сделать не могу. Вопрос как это сделать? Если вариантов несколько какой лучше? Или хотя бы куда смотреть?


Ответы (2 шт):

Автор решения: Gleb Kuznetsov

Ну к примеру что-то такое без всякого Reflection:

public class EnumDemo {

    private static final Map<String, EnumContainer<?>> lookup = Stream.of(Inner1.values(), Inner2.values())
            .flatMap(Stream::of)
            .collect(Collectors.toMap(EnumContainer::flatName, Function.identity()));

    interface EnumContainer<T> {
        List<T> valueList();

        String flatName();
    }

    enum Inner1 implements EnumContainer<String> {
        Enum1(List.of("A", "B", "C")),
        Enum2(List.of("A", "B", "C", "D"));

        private final List<String> valueList;

        Inner1(List<String> valueList) {
            this.valueList = valueList;
        }

        @Override
        public List<String> valueList() {
            return valueList;
        }

        @Override
        public String flatName() {
            return Inner1.class.getSimpleName() + "." + this.name();
        }

    }

    enum Inner2 implements EnumContainer<Integer> {
        Enum3(List.of(1, 2, 3)),
        Enum4(List.of(1, 2, 3, 4));

        public final List<Integer> valueList;

        Inner2(List<Integer> valueList) {
            this.valueList = valueList;
        }

        @Override
        public List<Integer> valueList() {
            return valueList;
        }

        @Override
        public String flatName() {
            return Inner2.class.getSimpleName() + "." + this.name();
        }
    }

    private static String dumpEnum(String s) {
        return lookup.get(s).valueList().stream().map(Object::toString).collect(Collectors.joining(","));
    }

    public static void main(String[] args) {
        System.out.println(dumpEnum("Inner1.Enum1"));
        System.out.println(dumpEnum("Inner1.Enum2"));
        System.out.println(dumpEnum("Inner2.Enum3"));
        System.out.println(dumpEnum("Inner2.Enum4"));
    }
    
}

Конечно можно и с помощью Reflection. К примеру как-то так (заранее извиняюсь за стиль):

Optional<Class<?>> inner = Arrays.stream(EnumDemo.class.getDeclaredClasses())
        .filter(Class::isEnum)
        .filter(clazz -> clazz.getSimpleName().contains("Inner1"))
        .findFirst();

EnumContainer<?> o = inner.map(clazz -> {
            try {
                return clazz.getMethod("valueOf", String.class).invoke(null, "Enum1");
            } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
                e.printStackTrace();
            }
            return null;
        })
        .filter(r -> EnumContainer.class.isAssignableFrom(r.getClass()))
        .map(EnumContainer.class::cast)
        .get();
→ Ссылка
Автор решения: Денис Кондратов

В результате сделал нечто подобное. В реальности вложенность меньше за счёт использования отдельного метода для поиска класса. В целом смысл такой: парсим строку в которой указан путь - MainClass.Inner1.Enum2. Дальше получаем список классов MainClass.class.getDeclaredClasses() в нём ищем класс с именем из списка, затем в его списке классов ищем класс со следующим именем и т.д. пока не добираемся до enum класса. Откуда берем список enum значений cc.getEnumConstants().

for (int i = 0; i < MainClass.class.getDeclaredClasses().length; i++) {
    
        if(MainClass.class.getDeclaredClasses()[i].toString().contains("Inner1")){  
        
          Class<?> c = (MainClass.class.getDeclaredClasses()[i];
          
            for (int j = 0; j <c.class.getDeclaredClasses().length; j++) {
                
                if(c.class.getDeclaredClasses()[j].toString().contains("Status")){
                    Class<?> cc = c.class.getDeclaredClasses()[j]; 
                    System.out.println(cc.getEnumConstants());
                }
            }
        }
}
→ Ссылка