protected void processNestedEnumProperties(final List<ConfigurationMetadataProperty> properties,
                                               final List<ConfigurationMetadataProperty> groups) throws Exception {
        val propertiesToProcess = properties.stream()
            .filter(e -> {
                val matcher = NESTED_CLASS_PATTERN.matcher(e.getType());
                return matcher.matches();
            })
            .collect(Collectors.toSet());

        for (val prop : propertiesToProcess) {

            val matcher = NESTED_CLASS_PATTERN.matcher(prop.getType());
            if (!matcher.matches()) {
                throw new RuntimeException("Unable to find a match for " + prop.getType());
            }

            val parent = matcher.group(1);
            val innerType = matcher.group(2);
            var typePath = ConfigurationMetadataClassSourceLocator.buildTypeSourcePath(projectDirectory.getCanonicalPath(), parent);

            try {
                TypeDeclaration<?> primaryType = null;
                if (typePath.contains("$")) {
                    val innerClass = StringUtils.substringBetween(typePath, "$", ".");
                    typePath = StringUtils.remove(typePath, '$' + innerClass);
                    val cu = StaticJavaParser.parse(new File(typePath));
                    for (val type : cu.getTypes()) {
                        for (val member : type.getMembers()) {
                            if (member.isClassOrInterfaceDeclaration()) {
                                val name = member.asClassOrInterfaceDeclaration().getNameAsString();
                                if (name.equals(innerClass)) {
                                    primaryType = member.asClassOrInterfaceDeclaration();
                                    break;
                                }
                            }
                        }
                    }
                } else {
                    val cu = StaticJavaParser.parse(new File(typePath));
                    primaryType = cu.getPrimaryType().orElseThrow();
                }

                Objects.requireNonNull(primaryType).getMembers()
                    .stream()
                    .peek(member -> {
                        if (member.isFieldDeclaration()) {
                            var fieldDecl = member.asFieldDeclaration();
                            var variable = fieldDecl.getVariable(0);

                            if (variable.getInitializer().isPresent()) {
                                var beginIndex = prop.getName().lastIndexOf('.');
                                var propShortName = beginIndex != -1 ? prop.getName().substring(beginIndex + 1) : prop.getName();
                                var names = RelaxedPropertyNames.forCamelCase(variable.getNameAsString()).getValues();
                                if (names.contains(propShortName)) {
                                    variable.getInitializer().ifPresent(expression -> {
                                        val value = switch (expression) {
                                            case final LiteralStringValueExpr expr -> expr.getValue();
                                            case final BooleanLiteralExpr expr -> expr.getValue();
                                            case final FieldAccessExpr expr -> expr.getNameAsString();
                                            default -> null;
                                        };
                                        prop.setDefaultValue(value);
                                    });
                                }
                            }
                        }
                    })
                    .filter(member -> {
                        if (member.isEnumDeclaration()) {
                            val enumMem = member.asEnumDeclaration();
                            return enumMem.getNameAsString().equals(innerType);
                        }
                        if (member.isClassOrInterfaceDeclaration()) {
                            val typeName = member.asClassOrInterfaceDeclaration();
                            return typeName.getNameAsString().equals(innerType);
                        }
                        return false;
                    })
                    .forEach(member -> {
                        if (member.isEnumDeclaration()) {
                            val enumMem = member.asEnumDeclaration();
                            val builder = ConfigurationMetadataPropertyCreator.collectJavadocsEnumFields(prop, enumMem);
                            prop.setDescription(builder.toString());
                        }
                        if (member.isClassOrInterfaceDeclaration()) {
                            val typeName = member.asClassOrInterfaceDeclaration();
                            typeName.getFields()
                                .stream()
                                .filter(field -> !field.isStatic())
                                .forEach(field -> {
                                    val resultProps = new HashSet<ConfigurationMetadataProperty>();
                                    val resultGroups = new HashSet<ConfigurationMetadataProperty>();

                                    val creator = new ConfigurationMetadataPropertyCreator(
                                        false, resultProps, resultGroups, parent);
                                    creator.createConfigurationProperty(field, prop.getName());

                                    groups.addAll(resultGroups);
                                    properties.addAll(resultProps);
                                });
                        }
                    });
            } catch (final Exception ex) {
                throw new RuntimeException(ex);
            }
        }
    }
Main.

@param args the args
@throws Exception the exception
api/cas-server-core-api-configuration-model/src/main/java/org/apereo/cas/configuration/metadata/ConfigurationMetadataGenerator.java