public ConfigurationMetadataProperty createConfigurationProperty(final FieldDeclaration fieldDecl, final String propName) {
        val variable = fieldDecl.getVariables().getFirst().orElseThrow();
        val name = StreamSupport.stream(RelaxedPropertyNames.forCamelCase(variable.getNameAsString()).spliterator(), false)
            .map(Object::toString)
            .findFirst()
            .orElseGet(variable::getNameAsString);

        val indexedGroup = propName.concat(indexNameWithBrackets ? "[]" : StringUtils.EMPTY);
        val indexedName = indexedGroup.concat(".").concat(name);

        val prop = new ConfigurationMetadataProperty();

        if (fieldDecl.getJavadoc().isPresent()) {
            var description = StringUtils.EMPTY;
            if (indexedName.endsWith(".location")) {
                val groupProperty = properties.stream()
                    .filter(p -> p.getName().equalsIgnoreCase(indexedGroup))
                    .findFirst();
                if (groupProperty.isPresent()) {
                    description = groupProperty.get().getDescription() + '\n';
                }
            }
            description += fieldDecl.getJavadoc().get().getDescription().toText();

            prop.setDescription(description);
            prop.setShortDescription(StringUtils.substringBefore(description, "."));

        } else {
            LOGGER.error("No Javadoc found for field [{}]", indexedName);
        }
        prop.setName(indexedName);
        prop.setId(indexedName);

        var elementType = fieldDecl.getElementType();
        val elementTypeStr = elementType.asString();
        if (PRIMITIVES.containsKey(elementTypeStr)) {
            prop.setType(PRIMITIVES.get(elementTypeStr));
        } else if (elementTypeStr.startsWith("Map<") || elementTypeStr.startsWith("List<") || elementTypeStr.startsWith("Set<")) {
            prop.setType("java.util." + elementTypeStr);
            var typeName = elementTypeStr.substring(elementTypeStr.indexOf('<') + 1, elementTypeStr.indexOf('>'));
            var parent = fieldDecl.getParentNode().orElseThrow();
            parent.findFirst(EnumDeclaration.class, em -> em.getNameAsString().contains(typeName))
                .ifPresent(em -> {
                    var builder = collectJavadocsEnumFields(prop, em);
                    prop.setDescription(builder.toString());
                });
        } else {
            prop.setType(elementTypeStr);
            var parent = fieldDecl.getParentNode().orElseThrow();

            var enumDecl = parent.findFirst(EnumDeclaration.class, em -> em.getNameAsString().contains(elementTypeStr));
            if (enumDecl.isPresent()) {
                val em = enumDecl.get();
                val builder = collectJavadocsEnumFields(prop, em);
                prop.setDescription(builder.toString());
                em.getFullyQualifiedName().ifPresent(prop::setType);
            }
        }

        val initializer = variable.getInitializer();
        if (initializer.isPresent()) {
            val exp = initializer.get();
            try {
                val parentClassInstance = Class.forName(parentClass);
                if (!Modifier.isAbstract(parentClassInstance.getModifiers())) {
                    val classInstance = parentClassInstance.getConstructor().newInstance();
                    val propertyField = parentClassInstance.getDeclaredField(variable.getNameAsString());
                    propertyField.trySetAccessible();
                    val resultingValue = propertyField.get(classInstance);
                    val valueType = resultingValue.getClass();
                    if (valueType.isArray()) {
                        prop.setDefaultValue(Arrays.toString((Object[]) resultingValue));
                    } else if (resultingValue instanceof final Collection<?> results) {
                        if (!results.isEmpty()) {
                            val values = results.stream()
                                .map(Object::toString)
                                .collect(Collectors.joining(","));
                            prop.setDefaultValue(values);
                        }
                    } else if (valueType.isPrimitive() || valueType.isEnum()
                        || PRIMITIVES.containsKey(valueType.getSimpleName())
                        || PRIMITIVES.containsKey(elementTypeStr)) {
                        prop.setDefaultValue(resultingValue.toString());
                    } else if (resultingValue instanceof final Map<?, ?> mappedValue) {
                        if (!mappedValue.isEmpty()) {
                            LOGGER.warn("Found configuration property as a Map: [{}]:[{}] with values [{}]",
                                variable.getNameAsString(), valueType.getName(), mappedValue);
                        }
                    } else if (!parentClass.endsWith("Properties")) {
                        LOGGER.debug("Cannot determine default value; Unknown configuration property type [{}]:[{}]",
                            variable.getNameAsString(), valueType.getName());
                    }
                }
            } catch (final Exception e) {
                LOGGER.error("Processing [{}]:[{}]. Error [{}]", parentClass, name, e);
                switch (exp) {
                    case final LiteralStringValueExpr ex -> prop.setDefaultValue(ex.getValue());
                    case final BooleanLiteralExpr ex -> prop.setDefaultValue(ex.getValue());
                    case final FieldAccessExpr ex -> prop.setDefaultValue(ex.getNameAsString());
                    default -> {
                    }
                }
            }
        }

        LOGGER.debug("Collecting property [{}]", prop.getName());
        properties.add(prop);

        val grp = new ComparableConfigurationMetadataProperty();
        grp.setId(indexedGroup);
        grp.setName(indexedGroup);
        grp.setType(parentClass);
        LOGGER.debug("Collecting property [{}]", grp.getName());
        groups.add(grp);

        return prop;
    }
Create configuration property.

@param fieldDecl the field decl
@param propName  the prop name
@return the configuration metadata property
api/cas-server-core-api-configuration-model/src/main/java/org/apereo/cas/configuration/metadata/ConfigurationMetadataPropertyCreator.java