protected void processMappableProperties(final List<ConfigurationMetadataProperty> properties,
                                             final List<ConfigurationMetadataProperty> groups) {
        val collectedProps = new HashSet<ConfigurationMetadataProperty>();
        val collectedGroups = new HashSet<ConfigurationMetadataProperty>();

        properties.forEach(property -> {
            try {
                val matcher = MAP_TYPE_STRING_KEY_OBJECT_PATTERN.matcher(property.getType());
                if (matcher.matches()) {
                    val valueType = matcher.group(1);

                    val typePath = ConfigurationMetadataClassSourceLocator.buildTypeSourcePath(projectDirectory.getCanonicalPath(), valueType);
                    val typeFile = new File(typePath);

                    if (typeFile.exists()) {
                        val parser = new ConfigurationMetadataUnitParser(projectDirectory.getCanonicalPath());
                        property.setName(property.getName().concat(".[key]"));
                        property.setId(property.getName());
                        parser.parseCompilationUnit(collectedProps, collectedGroups, property, typePath,
                            valueType, false);
                    } else {
                        throw new RuntimeException(typePath + " does not exist");
                    }
                }
            } catch (final Exception e) {
                throw new RuntimeException(e);
            }
        });
        properties.addAll(collectedProps);
        groups.addAll(collectedGroups);
    }
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