diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/Constants.java b/core/processor/src/main/java/io/quarkus/annotation/processor/Constants.java index c664e4e5228bc..17895ba6a3180 100644 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/Constants.java +++ b/core/processor/src/main/java/io/quarkus/annotation/processor/Constants.java @@ -66,6 +66,7 @@ final public class Constants { public static final String ANNOTATION_CONFIG_WITH_NAME = "io.smallrye.config.WithName"; public static final String ANNOTATION_CONFIG_WITH_PARENT_NAME = "io.smallrye.config.WithParentName"; public static final String ANNOTATION_CONFIG_WITH_DEFAULT = "io.smallrye.config.WithDefault"; + public static final String ANNOTATION_CONFIG_WITH_UNNAMED_KEY = "io.smallrye.config.WithUnnamedKey"; public static final Set SUPPORTED_ANNOTATIONS_TYPES = Set.of(ANNOTATION_BUILD_STEP, ANNOTATION_CONFIG_GROUP, ANNOTATION_CONFIG_ROOT, ANNOTATION_RECORDER); diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocItemFinder.java b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocItemFinder.java index 39b569f7943a2..8d6c155ff072d 100644 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocItemFinder.java +++ b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocItemFinder.java @@ -8,6 +8,7 @@ import static io.quarkus.annotation.processor.Constants.ANNOTATION_CONFIG_WITH_DEFAULT; import static io.quarkus.annotation.processor.Constants.ANNOTATION_CONFIG_WITH_NAME; import static io.quarkus.annotation.processor.Constants.ANNOTATION_CONFIG_WITH_PARENT_NAME; +import static io.quarkus.annotation.processor.Constants.ANNOTATION_CONFIG_WITH_UNNAMED_KEY; import static io.quarkus.annotation.processor.Constants.ANNOTATION_CONVERT_WITH; import static io.quarkus.annotation.processor.Constants.ANNOTATION_DEFAULT_CONVERTER; import static io.quarkus.annotation.processor.Constants.DOT; @@ -22,6 +23,8 @@ import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.hyphenate; import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.hyphenateEnumValue; import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.stringifyType; +import static java.util.Collections.emptyList; +import static java.util.stream.Collectors.toList; import static javax.lang.model.element.Modifier.ABSTRACT; import java.io.IOException; @@ -167,6 +170,7 @@ private List recursivelyFindConfigItems(Element element, String r String hyphenatedFieldName = hyphenate(fieldName); String configDocMapKey = hyphenatedFieldName; + boolean unnamedMapKey = false; boolean isDeprecated = false; boolean generateDocumentation = true; ConfigDocSection configSection = new ConfigDocSection(); @@ -229,6 +233,8 @@ private List recursivelyFindConfigItems(Element element, String r defaultValueDoc = annotationMirror.getElementValues().values().iterator().next().getValue().toString(); } else if (annotationName.equals(ANNOTATION_CONFIG_WITH_DEFAULT)) { defaultValue = annotationMirror.getElementValues().values().iterator().next().getValue().toString(); + } else if (annotationName.equals(ANNOTATION_CONFIG_WITH_UNNAMED_KEY)) { + unnamedMapKey = true; } } @@ -250,7 +256,7 @@ private List recursivelyFindConfigItems(Element element, String r String type = getType(typeMirror); if (isConfigGroup(type)) { - List groupConfigItems = readConfigGroupItems(configPhase, rootName, name, type, + List groupConfigItems = readConfigGroupItems(configPhase, rootName, name, emptyList(), type, configSection, withinAMap, generateSeparateConfigGroupDocsFiles); DocGeneratorUtil.appendConfigItemsIntoExistingOnes(configDocItems, groupConfigItems); } else { @@ -273,9 +279,16 @@ private List recursivelyFindConfigItems(Element element, String r if (typeArguments.size() == 2) { type = getType(typeArguments.get(1)); if (isConfigGroup(type)) { - name += String.format(NAMED_MAP_CONFIG_ITEM_FORMAT, configDocMapKey); - List groupConfigItems = readConfigGroupItems(configPhase, rootName, name, type, - configSection, true, generateSeparateConfigGroupDocsFiles); + List additionalNames; + if (unnamedMapKey) { + additionalNames = List + .of(name + String.format(NAMED_MAP_CONFIG_ITEM_FORMAT, configDocMapKey)); + } else { + name += String.format(NAMED_MAP_CONFIG_ITEM_FORMAT, configDocMapKey); + additionalNames = emptyList(); + } + List groupConfigItems = readConfigGroupItems(configPhase, rootName, name, + additionalNames, type, configSection, true, generateSeparateConfigGroupDocsFiles); DocGeneratorUtil.appendConfigItemsIntoExistingOnes(configDocItems, groupConfigItems); continue; } else { @@ -301,7 +314,8 @@ private List recursivelyFindConfigItems(Element element, String r } configSection.setOptional(true); List groupConfigItems = readConfigGroupItems(configPhase, rootName, name, - typeInString, configSection, withinAMap, generateSeparateConfigGroupDocsFiles); + emptyList(), typeInString, configSection, withinAMap, + generateSeparateConfigGroupDocsFiles); DocGeneratorUtil.appendConfigItemsIntoExistingOnes(configDocItems, groupConfigItems); continue; } else if ((typeInString.startsWith(List.class.getName()) @@ -355,6 +369,7 @@ private List recursivelyFindConfigItems(Element element, String r } configDocKey.setKey(name); + configDocKey.setAdditionalKeys(emptyList()); configDocKey.setType(type); configDocKey.setList(list); configDocKey.setOptional(optional); @@ -509,8 +524,15 @@ private boolean isDurationType(TypeMirror realTypeMirror) { * configuration group if properly updated afterwards. * */ - private List readConfigGroupItems(ConfigPhase configPhase, String topLevelRootName, String parentName, - String configGroup, ConfigDocSection configSection, boolean withinAMap, boolean generateSeparateConfigGroupDocs) + private List readConfigGroupItems( + ConfigPhase configPhase, + String topLevelRootName, + String parentName, + List additionalNames, + String configGroup, + ConfigDocSection configSection, + boolean withinAMap, + boolean generateSeparateConfigGroupDocs) throws JsonProcessingException { configSection.setConfigGroupType(configGroup); @@ -534,8 +556,8 @@ private List readConfigGroupItems(ConfigPhase configPhase, String allConfigurationGroups.put(configGroup, OBJECT_MAPPER.writeValueAsString(groupConfigItems)); } - groupConfigItems = decorateGroupItems(groupConfigItems, configPhase, topLevelRootName, parentName, withinAMap, - generateSeparateConfigGroupDocs); + groupConfigItems = decorateGroupItems(groupConfigItems, configPhase, topLevelRootName, parentName, additionalNames, + withinAMap, generateSeparateConfigGroupDocs); // make sure that the config section is added if it is to be shown or when scanning parent configuration group // priory to scanning configuration roots. This is useful as we get indication of whether the config items are part @@ -561,8 +583,15 @@ private List readConfigGroupItems(ConfigPhase configPhase, String * The missing information come from configuration roots and these are config phase, top level root name and parent name (as * we are traversing down the tree) */ - private List decorateGroupItems(List groupConfigItems, ConfigPhase configPhase, - String topLevelRootName, String parentName, boolean withinAMap, boolean generateSeparateConfigGroupDocs) { + private List decorateGroupItems( + List groupConfigItems, + ConfigPhase configPhase, + String topLevelRootName, + String parentName, + List additionalNames, + boolean withinAMap, + boolean generateSeparateConfigGroupDocs) { + List decoratedItems = new ArrayList<>(); for (ConfigDocItem configDocItem : groupConfigItems) { if (configDocItem.isConfigKey()) { @@ -571,6 +600,15 @@ private List decorateGroupItems(List groupConfigIt configDocKey.setWithinAMap(configDocKey.isWithinAMap() || withinAMap); configDocKey.setWithinAConfigGroup(true); configDocKey.setTopLevelGrouping(topLevelRootName); + List additionalKeys = new ArrayList<>(); + for (String key : configDocKey.getAdditionalKeys()) { + additionalKeys.add(parentName + key); + for (String name : additionalNames) { + additionalKeys.add(name + key); + } + } + additionalKeys.addAll(additionalNames.stream().map(k -> k + configDocKey.getKey()).collect(toList())); + configDocKey.setAdditionalKeys(additionalKeys); configDocKey.setKey(parentName + configDocKey.getKey()); decoratedItems.add(configDocItem); } else { @@ -584,6 +622,7 @@ private List decorateGroupItems(List groupConfigIt configPhase, topLevelRootName, parentName, + additionalNames, section.isWithinAMap(), generateSeparateConfigGroupDocs); String configGroupType = section.getConfigGroupType(); diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocKey.java b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocKey.java index f961b4399b2ba..a853a0f92939e 100644 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocKey.java +++ b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocKey.java @@ -2,6 +2,7 @@ import java.io.IOException; import java.io.Writer; +import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.regex.Matcher; @@ -11,6 +12,7 @@ final public class ConfigDocKey implements ConfigDocElement, Comparable { private String type; private String key; + private List additionalKeys = new ArrayList<>(); private String configDoc; private boolean withinAMap; private String defaultValue; @@ -61,6 +63,14 @@ public void setKey(String key) { this.key = key; } + public List getAdditionalKeys() { + return additionalKeys; + } + + public void setAdditionalKeys(final List additionalKeys) { + this.additionalKeys = additionalKeys; + } + public void setTopLevelGrouping(String topLevelGrouping) { this.topLevelGrouping = topLevelGrouping; } diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/MavenConfigDocBuilder.java b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/MavenConfigDocBuilder.java index e55a495fbc1a3..16d3c31a23205 100644 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/MavenConfigDocBuilder.java +++ b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/MavenConfigDocBuilder.java @@ -76,6 +76,7 @@ public void addParam(String type, String name, String defaultValue, boolean requ final ConfigDocKey configDocKey = new ConfigDocKey(); configDocKey.setType(type); configDocKey.setKey(name); + configDocKey.setAdditionalKeys(List.of(name)); configDocKey.setConfigPhase(ConfigPhase.RUN_TIME); configDocKey.setDefaultValue(defaultValue == null ? Constants.EMPTY : defaultValue); if (description != null && !description.isBlank()) { diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/SummaryTableDocFormatter.java b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/SummaryTableDocFormatter.java index 654b484967c47..dd3756daa3bfd 100644 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/SummaryTableDocFormatter.java +++ b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/SummaryTableDocFormatter.java @@ -114,11 +114,19 @@ public void format(Writer writer, ConfigDocKey configDocKey) throws IOException String configKeyAnchor = configDocKey.isPassThroughMap() ? getAnchor(key + Constants.DASH + configDocKey.getDocMapKey()) : getAnchor(key); String anchor = anchorPrefix + configKeyAnchor; - writer.append(String.format(TABLE_ROW_FORMAT, - configDocKey.getConfigPhase().getIllustration(), - anchor, - anchor, - key, + + StringBuilder keys = new StringBuilder(); + keys.append( + String.format("%s [[%s]]`link:#%s[%s]`\n\n", configDocKey.getConfigPhase().getIllustration(), anchor, anchor, + key)); + for (String additionalKey : configDocKey.getAdditionalKeys()) { + if (!additionalKey.equals(key)) { + keys.append(String.format("`link:#%s[%s]`\n\n", anchor, additionalKey)); + } + } + + writer.append(String.format("\n\na|%s\n[.description]\n--\n%s\n--%s|%s %s\n|%s\n", + keys, // make sure nobody inserts a table cell separator here doc.replace("|", "\\|"), // if ConfigDocKey is enum, cell style operator must support block elements