diff --git a/bom/application/pom.xml b/bom/application/pom.xml
index 53acbb19b37937..bb7f0f689bb7c3 100644
--- a/bom/application/pom.xml
+++ b/bom/application/pom.xml
@@ -42,7 +42,7 @@
2.0
1.2
1.6.0
- 2.4.2
+ 2.4.3-SNAPSHOT
3.1.1
3.0.1
2.1.9
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/ExtensionLoader.java b/core/deployment/src/main/java/io/quarkus/deployment/ExtensionLoader.java
index 3451bbf361306e..7ed31a53809ef4 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/ExtensionLoader.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/ExtensionLoader.java
@@ -89,6 +89,7 @@
import io.quarkus.runtime.annotations.Recorder;
import io.quarkus.runtime.configuration.ConfigUtils;
import io.quarkus.runtime.configuration.QuarkusConfigFactory;
+import io.smallrye.config.ConfigMappings.ConfigClassWithPrefix;
import io.smallrye.config.KeyMap;
import io.smallrye.config.KeyMapBackedConfigSource;
import io.smallrye.config.NameIterator;
@@ -164,6 +165,10 @@ public static Consumer loadStepsFrom(ClassLoader classLoader,
builder.withSources(ds1, ds2, platformConfigSource, pcs);
}
+ for (ConfigClassWithPrefix mapping : reader.getBuildTimeVisibleMappings()) {
+ builder.withMapping(mapping.getKlass(), mapping.getPrefix());
+ }
+
if (configCustomizer != null) {
configCustomizer.accept(builder);
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/builditem/ConfigDescriptionBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/builditem/ConfigDescriptionBuildItem.java
index 4f50e314502380..abf783202df0f2 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/builditem/ConfigDescriptionBuildItem.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/builditem/ConfigDescriptionBuildItem.java
@@ -9,13 +9,11 @@
public final class ConfigDescriptionBuildItem extends MultiBuildItem implements Comparable {
private final String propertyName;
- private final Class> type;
private final String defaultValue;
private final String docs;
- public ConfigDescriptionBuildItem(String propertyName, Class> type, String defaultValue, String docs) {
+ public ConfigDescriptionBuildItem(String propertyName, String defaultValue, String docs) {
this.propertyName = propertyName;
- this.type = type;
this.defaultValue = defaultValue;
this.docs = docs;
}
@@ -24,10 +22,6 @@ public String getPropertyName() {
return propertyName;
}
- public Class> getType() {
- return type;
- }
-
public String getDefaultValue() {
return defaultValue;
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/configuration/BuildTimeConfigurationReader.java b/core/deployment/src/main/java/io/quarkus/deployment/configuration/BuildTimeConfigurationReader.java
index 57abae96f853c2..d1ce6c6cfcabf8 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/configuration/BuildTimeConfigurationReader.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/configuration/BuildTimeConfigurationReader.java
@@ -6,6 +6,7 @@
import static io.quarkus.deployment.util.ReflectUtil.toError;
import static io.quarkus.deployment.util.ReflectUtil.typeOfParameter;
import static io.quarkus.deployment.util.ReflectUtil.unwrapInvocationTargetException;
+import static io.smallrye.config.ConfigMappings.ConfigClassWithPrefix.configClassWithPrefix;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
@@ -55,6 +56,10 @@
import io.quarkus.runtime.configuration.ConfigurationException;
import io.quarkus.runtime.configuration.HyphenateEnumConverter;
import io.quarkus.runtime.configuration.NameIterator;
+import io.smallrye.config.ConfigMapping;
+import io.smallrye.config.ConfigMappings;
+import io.smallrye.config.ConfigMappings.ConfigClassWithPrefix;
+import io.smallrye.config.ConfigValue;
import io.smallrye.config.Converters;
import io.smallrye.config.EnvConfigSource;
import io.smallrye.config.Expressions;
@@ -69,14 +74,19 @@ public final class BuildTimeConfigurationReader {
final ConfigPatternMap buildTimePatternMap;
final ConfigPatternMap buildTimeRunTimePatternMap;
- final ConfigPatternMap bootstrapPatternMap;
final ConfigPatternMap runTimePatternMap;
+ final ConfigPatternMap bootstrapPatternMap;
- final List buildTimeVisibleRoots;
final List allRoots;
+ final List buildTimeVisibleRoots;
final boolean bootstrapRootsEmpty;
+ final List buildTimeMappings;
+ final List buildTimeRunTimeMappings;
+ final List runTimeMappings;
+ final List buildTimeVisibleMappings;
+
/**
* Construct a new instance.
*
@@ -85,12 +95,42 @@ public final class BuildTimeConfigurationReader {
public BuildTimeConfigurationReader(final List> configRoots) {
Assert.checkNotNullParam("configRoots", configRoots);
- List bootstrapRoots = new ArrayList<>();
- List runTimeRoots = new ArrayList<>();
- List buildTimeRunTimeRoots = new ArrayList<>();
List buildTimeRoots = new ArrayList<>();
+ List buildTimeRunTimeRoots = new ArrayList<>();
+ List runTimeRoots = new ArrayList<>();
+ List bootstrapRoots = new ArrayList<>();
+
+ buildTimeMappings = new ArrayList<>();
+ buildTimeRunTimeMappings = new ArrayList<>();
+ runTimeMappings = new ArrayList<>();
+
Map, GroupDefinition> groups = new HashMap<>();
for (Class> configRoot : configRoots) {
+ boolean isMapping = configRoot.isAnnotationPresent(ConfigMapping.class);
+ if (isMapping) {
+ ConfigPhase phase = ConfigPhase.BUILD_TIME;
+ // To retrieve config phase
+ ConfigRoot annotation = configRoot.getAnnotation(ConfigRoot.class);
+ if (annotation != null) {
+ if (!annotation.name().equals(ConfigItem.HYPHENATED_ELEMENT_NAME)) {
+ throw reportError(configRoot, "@ConfigRoot.name() is not allowed in combination with @ConfigMapping");
+ }
+
+ phase = annotation.phase();
+ }
+
+ ConfigClassWithPrefix mapping = configClassWithPrefix(configRoot);
+ if (phase.equals(ConfigPhase.BUILD_TIME)) {
+ buildTimeMappings.add(mapping);
+ } else if (phase.equals(ConfigPhase.BUILD_AND_RUN_TIME_FIXED)) {
+ buildTimeRunTimeMappings.add(mapping);
+ } else if (phase.equals(ConfigPhase.RUN_TIME)) {
+ runTimeMappings.add(mapping);
+ }
+
+ continue;
+ }
+
String name = ConfigItem.HYPHENATED_ELEMENT_NAME;
ConfigPhase phase = ConfigPhase.BUILD_TIME;
ConfigRoot annotation = configRoot.getAnnotation(ConfigRoot.class);
@@ -115,10 +155,11 @@ public BuildTimeConfigurationReader(final List> configRoots) {
}
}
- bootstrapPatternMap = PatternMapBuilder.makePatterns(bootstrapRoots);
- runTimePatternMap = PatternMapBuilder.makePatterns(runTimeRoots);
- buildTimeRunTimePatternMap = PatternMapBuilder.makePatterns(buildTimeRunTimeRoots);
+ // ConfigRoots
buildTimePatternMap = PatternMapBuilder.makePatterns(buildTimeRoots);
+ buildTimeRunTimePatternMap = PatternMapBuilder.makePatterns(buildTimeRunTimeRoots);
+ runTimePatternMap = PatternMapBuilder.makePatterns(runTimeRoots);
+ bootstrapPatternMap = PatternMapBuilder.makePatterns(bootstrapRoots);
buildTimeVisibleRoots = new ArrayList<>(buildTimeRoots.size() + buildTimeRunTimeRoots.size());
buildTimeVisibleRoots.addAll(buildTimeRoots);
@@ -126,13 +167,15 @@ public BuildTimeConfigurationReader(final List> configRoots) {
bootstrapRootsEmpty = bootstrapRoots.isEmpty();
- List allRoots = new ArrayList<>(
- buildTimeVisibleRoots.size() + bootstrapRoots.size() + runTimeRoots.size());
+ allRoots = new ArrayList<>(buildTimeVisibleRoots.size() + bootstrapRoots.size() + runTimeRoots.size());
allRoots.addAll(buildTimeVisibleRoots);
allRoots.addAll(bootstrapRoots);
allRoots.addAll(runTimeRoots);
- this.allRoots = allRoots;
+ // ConfigMappings
+ buildTimeVisibleMappings = new ArrayList<>(buildTimeMappings.size() + buildTimeRunTimeMappings.size());
+ buildTimeVisibleMappings.addAll(buildTimeMappings);
+ buildTimeVisibleMappings.addAll(buildTimeRunTimeMappings);
}
private static void processClass(ClassDefinition.Builder builder, Class> clazz,
@@ -251,6 +294,18 @@ public List getAllRoots() {
return allRoots;
}
+ public List getBuildTimeMappings() {
+ return buildTimeMappings;
+ }
+
+ public List getBuildTimeRunTimeMappings() {
+ return buildTimeRunTimeMappings;
+ }
+
+ public List getBuildTimeVisibleMappings() {
+ return buildTimeVisibleMappings;
+ }
+
public ReadResult readConfiguration(final SmallRyeConfig config) {
return new ReadOperation(config).run();
}
@@ -301,7 +356,8 @@ ReadResult run() {
}
// sweep-up
SmallRyeConfig runtimeDefaultsConfig = getConfigForRuntimeDefaults();
- for (String propertyName : getAllProperties()) {
+ Set allProperties = getAllProperties();
+ for (String propertyName : allProperties) {
if (propertyName.equals(ConfigSource.CONFIG_ORDINAL)) {
continue;
}
@@ -393,10 +449,60 @@ ReadResult run() {
() -> runtimeDefaultsConfig.getOptionalValue(propertyName, String.class).orElse("")));
}
}
- return new ReadResult(objectsByRootClass, specifiedRunTimeDefaultValues, buildTimeRunTimeVisibleValues,
- allBuildTimeValues,
- buildTimePatternMap, buildTimeRunTimePatternMap, bootstrapPatternMap, runTimePatternMap, allRoots,
- bootstrapRootsEmpty);
+
+ // ConfigMappings
+ for (ConfigClassWithPrefix mapping : buildTimeVisibleMappings) {
+ objectsByRootClass.put(mapping.getKlass(), config.getConfigMapping(mapping.getKlass(), mapping.getPrefix()));
+ }
+
+ // Build Time Values Recording
+ for (ConfigClassWithPrefix mapping : buildTimeMappings) {
+ Set mappedProperties = ConfigMappings.mappedProperties(mapping, allProperties);
+ for (String property : mappedProperties) {
+ ConfigValue value = config.getConfigValue(property);
+ if (value != null && value.getRawValue() != null) {
+ allBuildTimeValues.put(property, value.getRawValue());
+ }
+ }
+ }
+
+ // Build Time and Run Time Values Recording
+ for (ConfigClassWithPrefix mapping : buildTimeRunTimeMappings) {
+ Set mappedProperties = ConfigMappings.mappedProperties(mapping, allProperties);
+ for (String property : mappedProperties) {
+ ConfigValue value = config.getConfigValue(property);
+ if (value != null && value.getRawValue() != null) {
+ allBuildTimeValues.put(property, value.getRawValue());
+ buildTimeRunTimeVisibleValues.put(property, value.getRawValue());
+ }
+ }
+ }
+
+ // Run Time Values Recording
+ for (ConfigClassWithPrefix mapping : runTimeMappings) {
+ Set mappedProperties = ConfigMappings.mappedProperties(mapping, allProperties);
+ for (String property : mappedProperties) {
+ ConfigValue value = config.getConfigValue(property);
+ if (value != null && value.getRawValue() != null) {
+ specifiedRunTimeDefaultValues.put(property, value.getRawValue());
+ }
+ }
+ }
+
+ return new ReadResult.Builder().setObjectsByRootClass(objectsByRootClass)
+ .setAllBuildTimeValues(allBuildTimeValues)
+ .setBuildTimeRunTimeVisibleValues(buildTimeRunTimeVisibleValues)
+ .setSpecifiedRunTimeDefaultValues(specifiedRunTimeDefaultValues)
+ .setBuildTimePatternMap(buildTimePatternMap)
+ .setBuildTimeRunTimePatternMap(buildTimeRunTimePatternMap)
+ .setBootstrapPatternMap(bootstrapPatternMap)
+ .setRunTimePatternMap(runTimePatternMap)
+ .setAllRoots(allRoots)
+ .setBootstrapRootsEmpty(bootstrapRootsEmpty)
+ .setBuildTimeMappings(buildTimeMappings)
+ .setBuildTimeRunTimeMappings(buildTimeRunTimeMappings)
+ .setRunTimeMappings(runTimeMappings)
+ .createReadResult();
}
/**
@@ -769,62 +875,67 @@ private SmallRyeConfig getConfigForRuntimeDefaults() {
public static final class ReadResult {
final Map, Object> objectsByRootClass;
- final Map specifiedRunTimeDefaultValues;
- final Map buildTimeRunTimeVisibleValues;
+
final Map allBuildTimeValues;
+ final Map buildTimeRunTimeVisibleValues;
+ final Map specifiedRunTimeDefaultValues;
+
final ConfigPatternMap buildTimePatternMap;
final ConfigPatternMap buildTimeRunTimePatternMap;
final ConfigPatternMap bootstrapPatternMap;
final ConfigPatternMap runTimePatternMap;
- final Map, RootDefinition> runTimeRootsByClass;
- final List allRoots;
+
final boolean bootstrapRootsEmpty;
- ReadResult(final Map, Object> objectsByRootClass, final Map specifiedRunTimeDefaultValues,
- final Map buildTimeRunTimeVisibleValues,
- Map allBuildTimeValues,
- final ConfigPatternMap buildTimePatternMap,
- final ConfigPatternMap buildTimeRunTimePatternMap,
- final ConfigPatternMap bootstrapPatternMap,
- final ConfigPatternMap runTimePatternMap, final List allRoots,
- boolean bootstrapRootsEmpty) {
- this.objectsByRootClass = objectsByRootClass;
- this.specifiedRunTimeDefaultValues = specifiedRunTimeDefaultValues;
- this.buildTimeRunTimeVisibleValues = buildTimeRunTimeVisibleValues;
- this.buildTimePatternMap = buildTimePatternMap;
- this.buildTimeRunTimePatternMap = buildTimeRunTimePatternMap;
- this.bootstrapPatternMap = bootstrapPatternMap;
- this.runTimePatternMap = runTimePatternMap;
- this.allRoots = allRoots;
- this.bootstrapRootsEmpty = bootstrapRootsEmpty;
- this.allBuildTimeValues = allBuildTimeValues;
+ final List allRoots;
+ final Map, RootDefinition> runTimeRootsByClass;
+
+ final List buildTimeMappings;
+ final List buildTimeRunTimeMappings;
+ final List runTimeMappings;
+
+ public ReadResult(final Builder builder) {
+ this.objectsByRootClass = builder.getObjectsByRootClass();
+
+ this.allBuildTimeValues = builder.getAllBuildTimeValues();
+ this.buildTimeRunTimeVisibleValues = builder.getBuildTimeRunTimeVisibleValues();
+ this.specifiedRunTimeDefaultValues = builder.getSpecifiedRunTimeDefaultValues();
+
+ this.buildTimePatternMap = builder.getBuildTimePatternMap();
+ this.buildTimeRunTimePatternMap = builder.getBuildTimeRunTimePatternMap();
+ this.bootstrapPatternMap = builder.getBootstrapPatternMap();
+ this.runTimePatternMap = builder.getRunTimePatternMap();
+
+ this.bootstrapRootsEmpty = builder.isBootstrapRootsEmpty();
+
+ this.allRoots = builder.getAllRoots();
Map, RootDefinition> map = new HashMap<>();
for (RootDefinition root : allRoots) {
map.put(root.getConfigurationClass(), root);
}
- runTimeRootsByClass = map;
+ this.runTimeRootsByClass = map;
+
+ this.buildTimeMappings = builder.getBuildTimeMappings();
+ this.buildTimeRunTimeMappings = builder.getBuildTimeRunTimeMappings();
+ this.runTimeMappings = builder.getRunTimeMappings();
}
public Map, Object> getObjectsByRootClass() {
return objectsByRootClass;
}
- public Object requireRootObjectForClass(Class> clazz) {
- Object obj = objectsByRootClass.get(clazz);
- if (obj == null) {
- throw new IllegalStateException("No root found for " + clazz);
- }
- return obj;
- }
-
- public Map getSpecifiedRunTimeDefaultValues() {
- return specifiedRunTimeDefaultValues;
+ public Map getAllBuildTimeValues() {
+ return allBuildTimeValues;
}
public Map getBuildTimeRunTimeVisibleValues() {
return buildTimeRunTimeVisibleValues;
}
+ public Map getSpecifiedRunTimeDefaultValues() {
+ return specifiedRunTimeDefaultValues;
+ }
+
public ConfigPatternMap getBuildTimePatternMap() {
return buildTimePatternMap;
}
@@ -841,16 +952,36 @@ public ConfigPatternMap getRunTimePatternMap() {
return runTimePatternMap;
}
- public Map getAllBuildTimeValues() {
- return allBuildTimeValues;
+ public boolean isBootstrapRootsEmpty() {
+ return bootstrapRootsEmpty;
}
public List getAllRoots() {
return allRoots;
}
- public boolean isBootstrapRootsEmpty() {
- return bootstrapRootsEmpty;
+ public Map, RootDefinition> getRunTimeRootsByClass() {
+ return runTimeRootsByClass;
+ }
+
+ public List getBuildTimeMappings() {
+ return buildTimeMappings;
+ }
+
+ public List getBuildTimeRunTimeMappings() {
+ return buildTimeRunTimeMappings;
+ }
+
+ public List getRunTimeMappings() {
+ return runTimeMappings;
+ }
+
+ public Object requireRootObjectForClass(Class> clazz) {
+ Object obj = objectsByRootClass.get(clazz);
+ if (obj == null) {
+ throw new IllegalStateException("No root found for " + clazz);
+ }
+ return obj;
}
public RootDefinition requireRootDefinitionForClass(Class> clazz) {
@@ -860,5 +991,142 @@ public RootDefinition requireRootDefinitionForClass(Class> clazz) {
}
return def;
}
+
+ static class Builder {
+ private Map, Object> objectsByRootClass;
+ private Map allBuildTimeValues;
+ private Map buildTimeRunTimeVisibleValues;
+ private Map specifiedRunTimeDefaultValues;
+ private ConfigPatternMap buildTimePatternMap;
+ private ConfigPatternMap buildTimeRunTimePatternMap;
+ private ConfigPatternMap bootstrapPatternMap;
+ private ConfigPatternMap runTimePatternMap;
+ private List allRoots;
+ private boolean bootstrapRootsEmpty;
+ private List buildTimeMappings;
+ private List buildTimeRunTimeMappings;
+ private List runTimeMappings;
+
+ Map, Object> getObjectsByRootClass() {
+ return objectsByRootClass;
+ }
+
+ Builder setObjectsByRootClass(final Map, Object> objectsByRootClass) {
+ this.objectsByRootClass = objectsByRootClass;
+ return this;
+ }
+
+ Map getAllBuildTimeValues() {
+ return allBuildTimeValues;
+ }
+
+ Builder setAllBuildTimeValues(final Map allBuildTimeValues) {
+ this.allBuildTimeValues = allBuildTimeValues;
+ return this;
+ }
+
+ Map getBuildTimeRunTimeVisibleValues() {
+ return buildTimeRunTimeVisibleValues;
+ }
+
+ Builder setBuildTimeRunTimeVisibleValues(final Map buildTimeRunTimeVisibleValues) {
+ this.buildTimeRunTimeVisibleValues = buildTimeRunTimeVisibleValues;
+ return this;
+ }
+
+ Map getSpecifiedRunTimeDefaultValues() {
+ return specifiedRunTimeDefaultValues;
+ }
+
+ Builder setSpecifiedRunTimeDefaultValues(final Map specifiedRunTimeDefaultValues) {
+ this.specifiedRunTimeDefaultValues = specifiedRunTimeDefaultValues;
+ return this;
+ }
+
+ ConfigPatternMap getBuildTimePatternMap() {
+ return buildTimePatternMap;
+ }
+
+ Builder setBuildTimePatternMap(final ConfigPatternMap buildTimePatternMap) {
+ this.buildTimePatternMap = buildTimePatternMap;
+ return this;
+ }
+
+ ConfigPatternMap getBuildTimeRunTimePatternMap() {
+ return buildTimeRunTimePatternMap;
+ }
+
+ Builder setBuildTimeRunTimePatternMap(final ConfigPatternMap buildTimeRunTimePatternMap) {
+ this.buildTimeRunTimePatternMap = buildTimeRunTimePatternMap;
+ return this;
+ }
+
+ ConfigPatternMap getBootstrapPatternMap() {
+ return bootstrapPatternMap;
+ }
+
+ Builder setBootstrapPatternMap(final ConfigPatternMap bootstrapPatternMap) {
+ this.bootstrapPatternMap = bootstrapPatternMap;
+ return this;
+ }
+
+ ConfigPatternMap getRunTimePatternMap() {
+ return runTimePatternMap;
+ }
+
+ Builder setRunTimePatternMap(final ConfigPatternMap runTimePatternMap) {
+ this.runTimePatternMap = runTimePatternMap;
+ return this;
+ }
+
+ List getAllRoots() {
+ return allRoots;
+ }
+
+ Builder setAllRoots(final List allRoots) {
+ this.allRoots = allRoots;
+ return this;
+ }
+
+ boolean isBootstrapRootsEmpty() {
+ return bootstrapRootsEmpty;
+ }
+
+ Builder setBootstrapRootsEmpty(final boolean bootstrapRootsEmpty) {
+ this.bootstrapRootsEmpty = bootstrapRootsEmpty;
+ return this;
+ }
+
+ List getBuildTimeMappings() {
+ return buildTimeMappings;
+ }
+
+ Builder setBuildTimeMappings(final List buildTimeMappings) {
+ this.buildTimeMappings = buildTimeMappings;
+ return this;
+ }
+
+ List getBuildTimeRunTimeMappings() {
+ return buildTimeRunTimeMappings;
+ }
+
+ Builder setBuildTimeRunTimeMappings(final List buildTimeRunTimeMappings) {
+ this.buildTimeRunTimeMappings = buildTimeRunTimeMappings;
+ return this;
+ }
+
+ List getRunTimeMappings() {
+ return runTimeMappings;
+ }
+
+ Builder setRunTimeMappings(final List runTimeMappings) {
+ this.runTimeMappings = runTimeMappings;
+ return this;
+ }
+
+ ReadResult createReadResult() {
+ return new ReadResult(this);
+ }
+ }
}
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/configuration/ConfigMappingUtils.java b/core/deployment/src/main/java/io/quarkus/deployment/configuration/ConfigMappingUtils.java
index 2cbe8dc5f73405..556c9434e00881 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/configuration/ConfigMappingUtils.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/configuration/ConfigMappingUtils.java
@@ -23,7 +23,6 @@
import org.jboss.jandex.MethodInfo;
import io.quarkus.deployment.annotations.BuildProducer;
-import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
import io.quarkus.deployment.builditem.ConfigClassBuildItem;
import io.quarkus.deployment.builditem.GeneratedClassBuildItem;
@@ -38,7 +37,6 @@ public class ConfigMappingUtils {
private ConfigMappingUtils() {
}
- @BuildStep
public static void generateConfigClasses(
CombinedIndexBuildItem combinedIndex,
BuildProducer generatedClasses,
@@ -46,6 +44,7 @@ public static void generateConfigClasses(
BuildProducer configClasses,
DotName configAnnotation) {
+ boolean isMapping = configAnnotation.equals(CONFIG_MAPPING_NAME);
for (AnnotationInstance instance : combinedIndex.getIndex().getAnnotations(configAnnotation)) {
AnnotationTarget target = instance.target();
AnnotationValue annotationPrefix = instance.value("prefix");
@@ -53,8 +52,8 @@ public static void generateConfigClasses(
if (target.kind().equals(FIELD)) {
if (annotationPrefix != null && !annotationPrefix.asString().equals(UNCONFIGURED_PREFIX)) {
configClasses.produce(
- toConfigClassBuildItem(instance, toClass(target.asField().type().name()),
- annotationPrefix.asString()));
+ toConfigClassBuildItem(toClass(target.asField().type().name()),
+ annotationPrefix.asString(), isMapping));
continue;
}
}
@@ -64,7 +63,7 @@ public static void generateConfigClasses(
ClassType classType = target.asMethodParameter().method().parameters()
.get(target.asMethodParameter().position()).asClassType();
configClasses
- .produce(toConfigClassBuildItem(instance, toClass(classType.name()), annotationPrefix.asString()));
+ .produce(toConfigClassBuildItem(toClass(classType.name()), annotationPrefix.asString(), isMapping));
continue;
}
}
@@ -75,40 +74,54 @@ public static void generateConfigClasses(
Class> configClass = toClass(target.asClass().name());
String prefix = Optional.ofNullable(annotationPrefix).map(AnnotationValue::asString).orElse("");
+ processConfigClass(configClass, prefix, isMapping, combinedIndex, true, generatedClasses, reflectiveClasses,
+ configClasses);
+ }
+ }
- List configMappingsMetadata = ConfigMappingLoader.getConfigMappingsMetadata(configClass);
- Set generatedClassesNames = new HashSet<>();
- Set mappingsInfo = new HashSet<>();
- configMappingsMetadata.forEach(mappingMetadata -> {
- generatedClasses.produce(
- new GeneratedClassBuildItem(true, mappingMetadata.getClassName(), mappingMetadata.getClassBytes()));
- reflectiveClasses
- .produce(ReflectiveClassBuildItem.builder(mappingMetadata.getInterfaceType()).methods(true).build());
- reflectiveClasses
- .produce(ReflectiveClassBuildItem.builder(mappingMetadata.getClassName()).constructors(true).build());
-
- for (Class> parent : getHierarchy(mappingMetadata.getInterfaceType())) {
- reflectiveClasses.produce(ReflectiveClassBuildItem.builder(parent).methods(true).build());
- }
-
- generatedClassesNames.add(mappingMetadata.getClassName());
+ public static void processConfigClass(
+ Class> configClass,
+ String prefix,
+ boolean isMapping,
+ CombinedIndexBuildItem combinedIndex,
+ boolean isApplicationClass,
+ BuildProducer generatedClasses,
+ BuildProducer reflectiveClasses,
+ BuildProducer configClasses) {
+
+ List configMappingsMetadata = ConfigMappingLoader.getConfigMappingsMetadata(configClass);
+ Set generatedClassesNames = new HashSet<>();
+ Set mappingsInfo = new HashSet<>();
+ configMappingsMetadata.forEach(mappingMetadata -> {
+ generatedClasses.produce(
+ new GeneratedClassBuildItem(isApplicationClass, mappingMetadata.getClassName(),
+ mappingMetadata.getClassBytes()));
+ reflectiveClasses
+ .produce(ReflectiveClassBuildItem.builder(mappingMetadata.getInterfaceType()).methods(true).build());
+ reflectiveClasses
+ .produce(ReflectiveClassBuildItem.builder(mappingMetadata.getClassName()).constructors(true).build());
+
+ for (Class> parent : getHierarchy(mappingMetadata.getInterfaceType())) {
+ reflectiveClasses.produce(ReflectiveClassBuildItem.builder(parent).methods(true).build());
+ }
- ClassInfo mappingInfo = combinedIndex.getIndex()
- .getClassByName(DotName.createSimple(mappingMetadata.getInterfaceType().getName()));
- if (mappingInfo != null) {
- mappingsInfo.add(mappingInfo);
- }
- });
+ generatedClassesNames.add(mappingMetadata.getClassName());
- // For implicit converters
- for (ClassInfo classInfo : mappingsInfo) {
- for (MethodInfo method : classInfo.methods()) {
- reflectiveClasses.produce(new ReflectiveClassBuildItem(true, false, method.returnType().name().toString()));
- }
+ ClassInfo mappingInfo = combinedIndex.getIndex()
+ .getClassByName(DotName.createSimple(mappingMetadata.getInterfaceType().getName()));
+ if (mappingInfo != null) {
+ mappingsInfo.add(mappingInfo);
}
+ });
- configClasses.produce(toConfigClassBuildItem(instance, configClass, generatedClassesNames, prefix));
+ // For implicit converters
+ for (ClassInfo classInfo : mappingsInfo) {
+ for (MethodInfo method : classInfo.methods()) {
+ reflectiveClasses.produce(new ReflectiveClassBuildItem(true, false, method.returnType().name().toString()));
+ }
}
+
+ configClasses.produce(toConfigClassBuildItem(configClass, prefix, isMapping, generatedClassesNames));
}
private static Class> toClass(DotName dotName) {
@@ -121,22 +134,18 @@ private static Class> toClass(DotName dotName) {
}
private static ConfigClassBuildItem toConfigClassBuildItem(
- AnnotationInstance instance,
Class> configClass,
- String prefix) {
- return toConfigClassBuildItem(instance, configClass, emptySet(), prefix);
+ String prefix,
+ boolean isMapping) {
+ return toConfigClassBuildItem(configClass, prefix, isMapping, emptySet());
}
private static ConfigClassBuildItem toConfigClassBuildItem(
- AnnotationInstance instance,
Class> configClass,
- Set generatedClasses,
- String prefix) {
- if (instance.name().equals(CONFIG_MAPPING_NAME)) {
- return new ConfigClassBuildItem(configClass, generatedClasses, prefix, MAPPING);
- } else {
- return new ConfigClassBuildItem(configClass, generatedClasses, prefix, PROPERTIES);
- }
+ String prefix,
+ boolean isMapping,
+ Set generatedClasses) {
+ return new ConfigClassBuildItem(configClass, generatedClasses, prefix, isMapping ? MAPPING : PROPERTIES);
}
private static List> getHierarchy(Class> mapping) {
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/configuration/RunTimeConfigurationGenerator.java b/core/deployment/src/main/java/io/quarkus/deployment/configuration/RunTimeConfigurationGenerator.java
index 377bac70e18c28..25db34905b30f7 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/configuration/RunTimeConfigurationGenerator.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/configuration/RunTimeConfigurationGenerator.java
@@ -113,8 +113,10 @@ public final class RunTimeConfigurationGenerator {
static final FieldDescriptor C_SPECIFIED_RUN_TIME_CONFIG_SOURCE = FieldDescriptor.of(CONFIG_CLASS_NAME,
"specifiedRunTimeConfigSource",
ConfigSource.class);
- static final FieldDescriptor C_UNUSED = FieldDescriptor.of(CONFIG_CLASS_NAME, "unused", List.class);
- static final FieldDescriptor C_UNUSED_RUNTIME = FieldDescriptor.of(CONFIG_CLASS_NAME, "unusedRuntime", List.class);
+ static final FieldDescriptor C_UNKNOWN = FieldDescriptor.of(CONFIG_CLASS_NAME, "unknown", List.class);
+ static final FieldDescriptor C_UNKNOWN_RUNTIME = FieldDescriptor.of(CONFIG_CLASS_NAME, "unknownRuntime", List.class);
+ static final MethodDescriptor C_REPORT_UNKNOWN = MethodDescriptor.ofMethod(CONFIG_CLASS_NAME, "reportUnknown", void.class,
+ String.class, List.class);
static final MethodDescriptor CD_INVALID_VALUE = MethodDescriptor.ofMethod(ConfigDiagnostic.class, "invalidValue",
void.class, String.class, IllegalArgumentException.class);
@@ -182,6 +184,9 @@ public final class RunTimeConfigurationGenerator {
static final MethodDescriptor RCSP_NEW = MethodDescriptor.ofConstructor(RuntimeConfigSourceProvider.class, String.class);
static final MethodDescriptor RCSF_NEW = MethodDescriptor.ofConstructor(RuntimeConfigSourceFactory.class, String.class);
+ static final MethodDescriptor CS_GET_VALUE = MethodDescriptor.ofMethod(ConfigSource.class, "getValue", String.class,
+ String.class);
+
static final MethodDescriptor AL_NEW = MethodDescriptor.ofConstructor(ArrayList.class);
static final MethodDescriptor AL_ADD = MethodDescriptor.ofMethod(ArrayList.class, "add", boolean.class, Object.class);
@@ -283,6 +288,7 @@ public static final class GenerateOperation implements AutoCloseable {
final ResultHandle clinitNameBuilder;
final BuildTimeConfigurationReader.ReadResult buildTimeConfigResult;
final List roots;
+ final Map allBuildTimeValues;
// default values given in the build configuration
final Map specifiedRunTimeDefaultValues;
final Map buildTimeRunTimeVisibleValues;
@@ -324,6 +330,7 @@ public static final class GenerateOperation implements AutoCloseable {
this.devMode = builder.launchMode == LaunchMode.DEVELOPMENT;
final BuildTimeConfigurationReader.ReadResult buildTimeReadResult = builder.buildTimeReadResult;
buildTimeConfigResult = Assert.checkNotNullParam("buildTimeReadResult", buildTimeReadResult);
+ allBuildTimeValues = Assert.checkNotNullParam("allBuildTimeValues", buildTimeReadResult.getAllBuildTimeValues());
specifiedRunTimeDefaultValues = Assert.checkNotNullParam("specifiedRunTimeDefaultValues",
buildTimeReadResult.getSpecifiedRunTimeDefaultValues());
buildTimeRunTimeVisibleValues = Assert.checkNotNullParam("buildTimeRunTimeVisibleValues",
@@ -359,11 +366,11 @@ public static final class GenerateOperation implements AutoCloseable {
clinit = cc.getMethodCreator(MethodDescriptor.ofMethod(CONFIG_CLASS_NAME, "", void.class));
clinit.setModifiers(Opcodes.ACC_STATIC);
- cc.getFieldCreator(C_UNUSED).setModifiers(Opcodes.ACC_STATIC | Opcodes.ACC_FINAL);
- clinit.writeStaticField(C_UNUSED, clinit.newInstance(AL_NEW));
+ cc.getFieldCreator(C_UNKNOWN).setModifiers(Opcodes.ACC_STATIC | Opcodes.ACC_FINAL);
+ clinit.writeStaticField(C_UNKNOWN, clinit.newInstance(AL_NEW));
- cc.getFieldCreator(C_UNUSED_RUNTIME).setModifiers(Opcodes.ACC_STATIC | Opcodes.ACC_FINAL);
- clinit.writeStaticField(C_UNUSED_RUNTIME, clinit.newInstance(AL_NEW));
+ cc.getFieldCreator(C_UNKNOWN_RUNTIME).setModifiers(Opcodes.ACC_STATIC | Opcodes.ACC_FINAL);
+ clinit.writeStaticField(C_UNKNOWN_RUNTIME, clinit.newInstance(AL_NEW));
clinit.invokeStaticMethod(PM_SET_RUNTIME_DEFAULT_PROFILE, clinit.load(ProfileManager.getActiveProfile()));
clinitNameBuilder = clinit.newInstance(SB_NEW);
@@ -440,6 +447,8 @@ public static final class GenerateOperation implements AutoCloseable {
// block for converter setup
converterSetup = clinit.createScope();
+ reportUnknown(cc.getMethodCreator(C_REPORT_UNKNOWN));
+
// create readBootstrapConfig method - this will always exist whether or not it contains a method body
// the method body will be empty when there are no bootstrap configuration roots
readBootstrapConfig = cc.getMethodCreator(C_BOOTSTRAP_CONFIG);
@@ -809,8 +818,7 @@ public void run() {
// generate sweep for clinit
configSweepLoop(siParserBody, clinit, clinitConfig);
- clinit.invokeStaticMethod(CD_UNKNOWN_PROPERTIES,
- clinit.readStaticField(FieldDescriptor.of(cc.getClassName(), "unused", List.class)));
+ clinit.invokeStaticMethod(CD_UNKNOWN_PROPERTIES, clinit.readStaticField(C_UNKNOWN));
if (devMode) {
configSweepLoop(siParserBody, readConfig, runTimeConfig);
@@ -818,8 +826,7 @@ public void run() {
// generate sweep for run time
configSweepLoop(rtParserBody, readConfig, runTimeConfig);
- readConfig.invokeStaticMethod(CD_UNKNOWN_PROPERTIES_RT,
- readConfig.readStaticField(FieldDescriptor.of(cc.getClassName(), "unusedRuntime", List.class)));
+ readConfig.invokeStaticMethod(CD_UNKNOWN_PROPERTIES_RT, readConfig.readStaticField(C_UNKNOWN_RUNTIME));
if (bootstrapConfigSetupNeeded()) {
// generate sweep for bootstrap config
@@ -1657,16 +1664,56 @@ private FieldDescriptor getOrCreateConverterInstance(Field field, ConverterType
return fd;
}
- private void reportUnknown(BytecodeCreator methodCreator, ResultHandle unusedProperty) {
- ResultHandle unused = methodCreator.readStaticField(C_UNUSED);
- methodCreator.invokeVirtualMethod(AL_ADD, unused,
- methodCreator.invokeVirtualMethod(NI_GET_NAME, unusedProperty));
+ private void reportUnknown(final MethodCreator mc) {
+ mc.setModifiers(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC);
+
+ ResultHandle unknownProperty = mc.getMethodParam(0);
+
+ // Ignore all build property names. This is to ignore any properties mapped with @ConfigMapping, because
+ // these do not fall into the ignore ConfigPattern.
+ for (String buildTimeProperty : allBuildTimeValues.keySet()) {
+ ResultHandle equalsResult = mc.invokeVirtualMethod(
+ MethodDescriptor.ofMethod(Object.class, "equals", boolean.class, Object.class), unknownProperty,
+ mc.load(buildTimeProperty));
+ mc.ifTrue(equalsResult).trueBranch().returnValue(null);
+ }
+
+ ResultHandle unknown = mc.getMethodParam(1);
+
+ // Ignore recorded properties. If properties are present here, it means that they were recorded at build
+ // time as being mapped in a @ConfigMapping
+ ResultHandle buildTimeRunTimeSource = mc.readStaticField(C_BUILD_TIME_CONFIG_SOURCE);
+ ResultHandle buildTimeRunTimeValue = mc.invokeInterfaceMethod(CS_GET_VALUE, buildTimeRunTimeSource,
+ unknownProperty);
+ mc.ifNotNull(buildTimeRunTimeValue).trueBranch().returnValue(null);
+
+ ResultHandle buildTimeRunTimeDefaultsSource = mc.readStaticField(C_BUILD_TIME_RUN_TIME_DEFAULTS_CONFIG_SOURCE);
+ ResultHandle buildTimeRunTimeDefaultValue = mc.invokeInterfaceMethod(CS_GET_VALUE, buildTimeRunTimeDefaultsSource,
+ unknownProperty);
+ mc.ifNotNull(buildTimeRunTimeDefaultValue).trueBranch().returnValue(null);
+
+ ResultHandle runtimeSpecifiedSource = mc.readStaticField(C_SPECIFIED_RUN_TIME_CONFIG_SOURCE);
+ ResultHandle runtimeSpecifiedValue = mc.invokeInterfaceMethod(CS_GET_VALUE, runtimeSpecifiedSource,
+ unknownProperty);
+ mc.ifNotNull(runtimeSpecifiedValue).trueBranch().returnValue(null);
+
+ // Add the property as unknown only if all checks fail
+ mc.invokeVirtualMethod(AL_ADD, unknown, unknownProperty);
+
+ mc.returnValue(null);
+ mc.close();
+ }
+
+ private void reportUnknown(BytecodeCreator bc, ResultHandle unknownProperty) {
+ ResultHandle property = bc.invokeVirtualMethod(NI_GET_NAME, unknownProperty);
+ ResultHandle unknown = bc.readStaticField(C_UNKNOWN);
+ bc.invokeStaticMethod(C_REPORT_UNKNOWN, property, unknown);
}
- private void reportUnknownRuntime(BytecodeCreator methodCreator, ResultHandle unusedProperty) {
- ResultHandle unused = methodCreator.readStaticField(C_UNUSED_RUNTIME);
- methodCreator.invokeVirtualMethod(AL_ADD, unused,
- methodCreator.invokeVirtualMethod(NI_GET_NAME, unusedProperty));
+ private void reportUnknownRuntime(BytecodeCreator bc, ResultHandle unknownProperty) {
+ ResultHandle property = bc.invokeVirtualMethod(NI_GET_NAME, unknownProperty);
+ ResultHandle unknown = bc.readStaticField(C_UNKNOWN_RUNTIME);
+ bc.invokeStaticMethod(C_REPORT_UNKNOWN, property, unknown);
}
public void close() {
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigDescriptionBuildStep.java b/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigDescriptionBuildStep.java
index 5cd2005e2b343f..d1cec417c43699 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigDescriptionBuildStep.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigDescriptionBuildStep.java
@@ -3,8 +3,10 @@
import java.io.IOException;
import java.io.UncheckedIOException;
import java.lang.reflect.Field;
+import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import java.util.Properties;
import java.util.function.Consumer;
@@ -17,6 +19,11 @@
import io.quarkus.deployment.configuration.matching.Container;
import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.util.ClassPathUtils;
+import io.smallrye.config.ConfigMappingInterface.LeafProperty;
+import io.smallrye.config.ConfigMappingInterface.PrimitiveProperty;
+import io.smallrye.config.ConfigMappingInterface.Property;
+import io.smallrye.config.ConfigMappings;
+import io.smallrye.config.ConfigMappings.ConfigClassWithPrefix;
public class ConfigDescriptionBuildStep {
@@ -36,6 +43,9 @@ List createConfigDescriptions(
processConfig(config.getReadResult().getBuildTimeRunTimePatternMap(), ret, javadoc);
processConfig(config.getReadResult().getBootstrapPatternMap(), ret, javadoc);
processConfig(config.getReadResult().getRunTimePatternMap(), ret, javadoc);
+ processMappings(config.getReadResult().getBuildTimeMappings(), ret, javadoc);
+ processMappings(config.getReadResult().getBuildTimeRunTimeMappings(), ret, javadoc);
+ processMappings(config.getReadResult().getRunTimeMappings(), ret, javadoc);
return ret;
}
@@ -70,11 +80,42 @@ public void accept(Container node) {
}
}
String javadocKey = field.getDeclaringClass().getName().replace('$', '.') + '.' + field.getName();
- ret.add(new ConfigDescriptionBuildItem("quarkus." + node.getPropertyName(),
- node.findEnclosingClass().getConfigurationClass(),
- defVal, javadoc.getProperty(javadocKey)));
+ ret.add(new ConfigDescriptionBuildItem("quarkus." + node.getPropertyName(), defVal,
+ javadoc.getProperty(javadocKey)));
}
});
}
+ private void processMappings(List mappings, List descriptionBuildItems,
+ Properties javaDocProperties) {
+ for (ConfigClassWithPrefix mapping : mappings) {
+ Map properties = ConfigMappings.getProperties(mapping);
+ for (Map.Entry entry : properties.entrySet()) {
+ String propertyName = entry.getKey();
+ Property property = entry.getValue();
+ Method method = property.getMethod();
+
+ String defaultValue = null;
+ if (property instanceof PrimitiveProperty) {
+ PrimitiveProperty primitiveProperty = (PrimitiveProperty) property;
+ if (primitiveProperty.hasDefaultValue()) {
+ defaultValue = primitiveProperty.getDefaultValue();
+ } else if (primitiveProperty.getPrimitiveType() == boolean.class) {
+ defaultValue = "false";
+ } else if (primitiveProperty.getPrimitiveType() != char.class) {
+ defaultValue = "0";
+ }
+ } else if (property instanceof LeafProperty) {
+ LeafProperty leafProperty = (LeafProperty) property;
+ if (leafProperty.hasDefaultValue()) {
+ defaultValue = leafProperty.getDefaultValue();
+ }
+ }
+
+ String javadocKey = method.getDeclaringClass().getName().replace('$', '.') + '.' + method.getName();
+ descriptionBuildItems.add(
+ new ConfigDescriptionBuildItem(propertyName, defaultValue, javaDocProperties.getProperty(javadocKey)));
+ }
+ }
+ }
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigGenerationBuildStep.java b/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigGenerationBuildStep.java
index 76baaac11caab7..5b234b593e6a3b 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigGenerationBuildStep.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigGenerationBuildStep.java
@@ -31,6 +31,7 @@
import io.quarkus.deployment.annotations.Record;
import io.quarkus.deployment.builditem.AdditionalBootstrapConfigSourceProviderBuildItem;
import io.quarkus.deployment.builditem.AdditionalStaticInitConfigSourceProviderBuildItem;
+import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
import io.quarkus.deployment.builditem.ConfigClassBuildItem;
import io.quarkus.deployment.builditem.ConfigurationBuildItem;
import io.quarkus.deployment.builditem.ConfigurationTypeBuildItem;
@@ -43,6 +44,7 @@
import io.quarkus.deployment.builditem.SuppressNonRuntimeConfigChangedWarningBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
import io.quarkus.deployment.configuration.BuildTimeConfigurationReader;
+import io.quarkus.deployment.configuration.ConfigMappingUtils;
import io.quarkus.deployment.configuration.RunTimeConfigurationGenerator;
import io.quarkus.deployment.configuration.definition.ClassDefinition;
import io.quarkus.deployment.configuration.definition.RootDefinition;
@@ -78,6 +80,25 @@ void staticInitSources(
PropertiesLocationConfigSourceFactory.class.getName()));
}
+ @BuildStep
+ void extensionMappings(ConfigurationBuildItem configItem,
+ CombinedIndexBuildItem combinedIndex,
+ BuildProducer generatedClasses,
+ BuildProducer reflectiveClasses,
+ BuildProducer configClasses) {
+ List buildTimeRunTimeMappings = configItem.getReadResult().getBuildTimeRunTimeMappings();
+ for (ConfigClassWithPrefix buildTimeRunTimeMapping : buildTimeRunTimeMappings) {
+ ConfigMappingUtils.processConfigClass(buildTimeRunTimeMapping.getKlass(), buildTimeRunTimeMapping.getPrefix(), true,
+ combinedIndex, false, generatedClasses, reflectiveClasses, configClasses);
+ }
+
+ final List runTimeMappings = configItem.getReadResult().getRunTimeMappings();
+ for (ConfigClassWithPrefix runTimeMapping : runTimeMappings) {
+ ConfigMappingUtils.processConfigClass(runTimeMapping.getKlass(), runTimeMapping.getPrefix(), true, combinedIndex,
+ false, generatedClasses, reflectiveClasses, configClasses);
+ }
+ }
+
/**
* Generate the Config class that instantiates MP Config and holds all the config objects
*/
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 023756d3ad6124..31302719a27ac6 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
@@ -54,6 +54,7 @@ final public class Constants {
public static final String ANNOTATION_CONFIG_ITEM = "io.quarkus.runtime.annotations.ConfigItem";
public static final String ANNOTATION_BUILD_STEP = "io.quarkus.deployment.annotations.BuildStep";
public static final String ANNOTATION_CONFIG_ROOT = "io.quarkus.runtime.annotations.ConfigRoot";
+ public static final String ANNOTATION_CONFIG_MAPPING = "io.smallrye.config.ConfigMapping";
public static final String ANNOTATION_DEFAULT_CONVERTER = "io.quarkus.runtime.annotations.DefaultConverter";
public static final String ANNOTATION_CONVERT_WITH = "io.quarkus.runtime.annotations.ConvertWith";
public static final String ANNOTATION_CONFIG_GROUP = "io.quarkus.runtime.annotations.ConfigGroup";
diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/ExtensionAnnotationProcessor.java b/core/processor/src/main/java/io/quarkus/annotation/processor/ExtensionAnnotationProcessor.java
index cc7c803eed7932..351573a63999fb 100644
--- a/core/processor/src/main/java/io/quarkus/annotation/processor/ExtensionAnnotationProcessor.java
+++ b/core/processor/src/main/java/io/quarkus/annotation/processor/ExtensionAnnotationProcessor.java
@@ -374,6 +374,37 @@ private void recordConfigJavadoc(TypeElement clazz) {
default:
}
}
+ writeJavadocProperties(clazz, javadocProps);
+ }
+
+ private void recordMappingJavadoc(TypeElement clazz) {
+ String className = clazz.getQualifiedName().toString();
+ if (!generatedJavaDocs.add(className))
+ return;
+ final Properties javadocProps = new Properties();
+ recordMappingJavadoc(clazz, javadocProps);
+ writeJavadocProperties(clazz, javadocProps);
+ }
+
+ private void recordMappingJavadoc(final TypeElement clazz, final Properties javadocProps) {
+ String className = clazz.getQualifiedName().toString();
+ for (Element e : clazz.getEnclosedElements()) {
+ switch (e.getKind()) {
+ case INTERFACE: {
+ recordMappingJavadoc(((TypeElement) e), javadocProps);
+ break;
+ }
+
+ case METHOD: {
+ processMethodConfigMapping((ExecutableElement) e, javadocProps, className);
+ break;
+ }
+ default:
+ }
+ }
+ }
+
+ private void writeJavadocProperties(final TypeElement clazz, final Properties javadocProps) {
if (javadocProps.isEmpty())
return;
final PackageElement pkg = processingEnv.getElementUtils().getPackageOf(clazz);
@@ -411,6 +442,11 @@ private void processMethodConfigItem(ExecutableElement method, Properties javado
javadocProps.put(className + Constants.DOT + buf.toString(), docComment);
}
+ private void processMethodConfigMapping(ExecutableElement method, Properties javadocProps, String className) {
+ final String docComment = getRequiredJavadoc(method);
+ javadocProps.put(className + Constants.DOT + method.getSimpleName().toString(), docComment);
+ }
+
private void processConfigGroup(RoundEnvironment roundEnv, TypeElement annotation) {
final Set groupClassNames = new HashSet<>();
for (TypeElement i : typesIn(roundEnv.getElementsAnnotatedWith(annotation))) {
@@ -442,8 +478,12 @@ private void processConfigRoot(RoundEnvironment roundEnv, TypeElement annotation
final String binaryName = processingEnv.getElementUtils().getBinaryName(clazz).toString();
if (rootClassNames.add(binaryName)) {
// new class
- recordConfigJavadoc(clazz);
- generateAccessor(clazz);
+ if (isAnnotationPresent(clazz, Constants.ANNOTATION_CONFIG_MAPPING)) {
+ recordMappingJavadoc(clazz);
+ } else if (isAnnotationPresent(clazz, Constants.ANNOTATION_CONFIG_ROOT)) {
+ recordConfigJavadoc(clazz);
+ generateAccessor(clazz);
+ }
final StringBuilder rbn = getRelativeBinaryName(clazz, new StringBuilder());
try {
final FileObject itemResource = processingEnv.getFiler().createResource(
@@ -628,7 +668,8 @@ private String getRequiredJavadoc(Element e) {
String docComment = processingEnv.getElementUtils().getDocComment(e);
if (docComment == null) {
- processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Unable to find javadoc for config item " + e, e);
+ processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
+ "Unable to find javadoc for config item " + e.getEnclosingElement() + " " + e, e);
return "";
}
diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDoItemFinder.java b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDoItemFinder.java
index 97133943a78903..2e15c17409873d 100644
--- a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDoItemFinder.java
+++ b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDoItemFinder.java
@@ -40,6 +40,7 @@
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
@@ -113,7 +114,8 @@ private List recursivelyFindConfigItems(Element element, String r
List configDocItems = new ArrayList<>();
TypeElement asTypeElement = (TypeElement) element;
TypeMirror superType = asTypeElement.getSuperclass();
- if (superType.getKind() != TypeKind.NONE) {
+
+ if (superType.getKind() != TypeKind.NONE && !superType.toString().equals(Object.class.getName())) {
String key = superType.toString();
String rawConfigItems = allConfigurationGroups.get(key);
if (rawConfigItems == null) {
@@ -129,11 +131,10 @@ private List recursivelyFindConfigItems(Element element, String r
}
configDocItems.addAll(superTypeConfigItems);
-
}
for (Element enclosedElement : element.getEnclosedElements()) {
- if (!enclosedElement.getKind().isField()) {
+ if (!enclosedElement.getKind().isField() && !enclosedElement.getKind().equals(ElementKind.METHOD)) {
continue;
}
@@ -237,8 +238,23 @@ private List recursivelyFindConfigItems(Element element, String r
boolean list = false;
boolean optional = false;
if (!typeMirror.getKind().isPrimitive()) {
- DeclaredType declaredType = (DeclaredType) typeMirror;
- TypeElement typeElement = (TypeElement) declaredType.asElement();
+ TypeElement typeElement;
+ DeclaredType declaredType;
+ if (typeMirror instanceof DeclaredType) {
+ declaredType = (DeclaredType) typeMirror;
+ typeElement = (TypeElement) declaredType.asElement();
+ } else if (typeMirror instanceof ExecutableType) {
+ ExecutableType executableType = (ExecutableType) typeMirror;
+ TypeMirror returnType = executableType.getReturnType();
+ if (returnType.getKind().isPrimitive()) {
+ continue;
+ }
+ declaredType = ((DeclaredType) returnType);
+ typeElement = (TypeElement) declaredType.asElement();
+ } else {
+ continue;
+ }
+
Name qualifiedName = typeElement.getQualifiedName();
optional = qualifiedName.toString().startsWith(Optional.class.getName())
|| qualifiedName.contentEquals(Map.class.getName());
diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocItemScanner.java b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocItemScanner.java
index f0cf97b161be17..3d7684a0ed05a7 100644
--- a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocItemScanner.java
+++ b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocItemScanner.java
@@ -50,7 +50,7 @@ public ConfigDocItemScanner() {
public void addConfigGroups(TypeElement configGroup) {
String configGroupName = configGroup.getQualifiedName().toString();
if (configGroupName.startsWith(IO_QUARKUS_TEST_EXTENSION_PACKAGE)) {
- return;
+ //return;
}
configGroupsToTypeElement.put(configGroupName, configGroup);
@@ -61,7 +61,7 @@ public void addConfigGroups(TypeElement configGroup) {
*/
public void addConfigRoot(final PackageElement pkg, TypeElement clazz) {
if (pkg.toString().startsWith(IO_QUARKUS_TEST_EXTENSION_PACKAGE)) {
- return;
+ //return;
}
ConfigPhase configPhase = ConfigPhase.BUILD_TIME;
@@ -82,7 +82,21 @@ public void addConfigRoot(final PackageElement pkg, TypeElement clazz) {
}
}
- if (name.isEmpty()) {
+ String prefix = null;
+ for (AnnotationMirror mirror : clazz.getAnnotationMirrors()) {
+ if (mirror.getAnnotationType().toString().equals(Constants.ANNOTATION_CONFIG_MAPPING)) {
+ for (Entry extends ExecutableElement, ? extends AnnotationValue> entry : mirror.getElementValues()
+ .entrySet()) {
+ if ("prefix()".equals(entry.getKey().toString())) {
+ prefix = entry.getValue().getValue().toString();
+ }
+ }
+ }
+ }
+
+ if (prefix != null) {
+ name = prefix;
+ } else if (name.isEmpty()) {
name = deriveConfigRootName(clazz.getSimpleName().toString(), configPhase);
} else if (name.endsWith(Constants.DOT + Constants.PARENT)) {
// take into account the root case which would contain characters that can't be used to create the final file
diff --git a/core/runtime/pom.xml b/core/runtime/pom.xml
index c29db610ab48f4..807e6137ee4ce5 100644
--- a/core/runtime/pom.xml
+++ b/core/runtime/pom.xml
@@ -211,7 +211,6 @@
org.wildfly.common:wildfly-common
io.smallrye.common:smallrye-common-io
-
io.smallrye:smallrye-config
diff --git a/core/test-extension/deployment/src/main/java/io/quarkus/extest/deployment/TestProcessor.java b/core/test-extension/deployment/src/main/java/io/quarkus/extest/deployment/TestProcessor.java
index 7c2aa916918cdf..76834fc87d92e5 100644
--- a/core/test-extension/deployment/src/main/java/io/quarkus/extest/deployment/TestProcessor.java
+++ b/core/test-extension/deployment/src/main/java/io/quarkus/extest/deployment/TestProcessor.java
@@ -20,6 +20,7 @@
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.BooleanSupplier;
@@ -39,10 +40,12 @@
import io.quarkus.arc.deployment.BeanArchiveIndexBuildItem;
import io.quarkus.arc.deployment.BeanContainerBuildItem;
import io.quarkus.arc.deployment.BeanDefiningAnnotationBuildItem;
+import io.quarkus.arc.deployment.ConfigPropertyBuildItem;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.Record;
import io.quarkus.deployment.builditem.AdditionalStaticInitConfigSourceProviderBuildItem;
+import io.quarkus.deployment.builditem.ConfigurationBuildItem;
import io.quarkus.deployment.builditem.FeatureBuildItem;
import io.quarkus.deployment.builditem.LaunchModeBuildItem;
import io.quarkus.deployment.builditem.LogHandlerBuildItem;
@@ -66,6 +69,8 @@
import io.quarkus.extest.runtime.config.TestBuildAndRunTimeConfig;
import io.quarkus.extest.runtime.config.TestBuildTimeConfig;
import io.quarkus.extest.runtime.config.TestConfigRoot;
+import io.quarkus.extest.runtime.config.TestMappingBuildTime;
+import io.quarkus.extest.runtime.config.TestMappingBuildTimeRunTime;
import io.quarkus.extest.runtime.config.TestRunTimeConfig;
import io.quarkus.extest.runtime.config.XmlConfig;
import io.quarkus.extest.runtime.logging.AdditionalLogHandlerValueFactory;
@@ -340,6 +345,48 @@ void checkConfig() {
}
}
+ @BuildStep
+ void configMapping(BuildProducer configProperties,
+ ConfigurationBuildItem configItem,
+ TestMappingBuildTime testMappingBuildTime,
+ TestMappingBuildTimeRunTime testMappingBuildTimeRunTime) {
+ Map buildTimeValues = configItem.getReadResult().getAllBuildTimeValues();
+ Map buildTimeRunTimeValues = configItem.getReadResult().getBuildTimeRunTimeVisibleValues();
+
+ if (!testMappingBuildTime.value().equals("value")
+ || !buildTimeValues.getOrDefault("quarkus.mapping.bt.value", "").equals("value")) {
+ throw new IllegalStateException();
+ }
+
+ if (!testMappingBuildTime.group().value().equals("value")
+ || !buildTimeValues.getOrDefault("quarkus.mapping.bt.group.value", "").equals("value")) {
+ throw new IllegalStateException();
+ }
+
+ if (testMappingBuildTime.missing().isPresent()) {
+ throw new IllegalStateException();
+ }
+
+ if (testMappingBuildTime.present().isEmpty() || !testMappingBuildTime.present().get().value().equals("present")
+ || !buildTimeValues.getOrDefault("quarkus.mapping.bt.present.value", "").equals("present")) {
+ throw new IllegalStateException();
+ }
+
+ if (testMappingBuildTime.groups().isEmpty()
+ || !buildTimeValues.getOrDefault("quarkus.mapping.bt.groups[0].value", "").equals("first")
+ || !buildTimeValues.getOrDefault("quarkus.mapping.bt.groups[1].value", "").equals("second"))
+
+ if (!testMappingBuildTimeRunTime.value().equals("value")
+ || !buildTimeRunTimeValues.getOrDefault("quarkus.mapping.btrt.value", "").equals("value")) {
+ throw new IllegalStateException();
+ }
+
+ if (!testMappingBuildTimeRunTime.group().value().equals("value")
+ || !buildTimeRunTimeValues.getOrDefault("quarkus.mapping.btrt.group.value", "").equals("value")) {
+ throw new IllegalStateException();
+ }
+ }
+
/**
* Collect the beans with our custom bean defining annotation and configure them with the runtime config
*
diff --git a/core/test-extension/deployment/src/main/resources/application.properties b/core/test-extension/deployment/src/main/resources/application.properties
index ba740ffec768cb..b79781807287f5 100644
--- a/core/test-extension/deployment/src/main/resources/application.properties
+++ b/core/test-extension/deployment/src/main/resources/application.properties
@@ -148,3 +148,16 @@ quarkus.http.ssl.port=4443
### Do not record env values in build time
bt.do.not.record=properties
+
+### mappings
+quarkus.mapping.bt.value=value
+quarkus.mapping.bt.group.value=value
+quarkus.mapping.bt.present.value=present
+quarkus.mapping.bt.groups[0].value=first
+quarkus.mapping.bt.groups[1].value=second
+
+quarkus.mapping.btrt.value=value
+quarkus.mapping.btrt.group.value=value
+
+quarkus.mapping.rt.value=value
+quarkus.mapping.rt.group.value=value
diff --git a/core/test-extension/deployment/src/test/java/io/quarkus/config/BuildTimeConfigTest.java b/core/test-extension/deployment/src/test/java/io/quarkus/config/BuildTimeConfigTest.java
index 6eddbc3541a007..4bfc5b396c4518 100644
--- a/core/test-extension/deployment/src/test/java/io/quarkus/config/BuildTimeConfigTest.java
+++ b/core/test-extension/deployment/src/test/java/io/quarkus/config/BuildTimeConfigTest.java
@@ -9,6 +9,8 @@
import java.nio.file.Paths;
import org.eclipse.microprofile.config.ConfigProvider;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
@@ -30,6 +32,8 @@ public class BuildTimeConfigTest {
@RegisterExtension
static final QuarkusUnitTest config = new QuarkusUnitTest()
+ .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class))
+ .withConfigurationResource("application.properties")
.overrideConfigKey("test-map-config", testFile.getAbsolutePath());
/**
diff --git a/core/test-extension/deployment/src/test/java/io/quarkus/extest/ConfigMappingTest.java b/core/test-extension/deployment/src/test/java/io/quarkus/extest/ConfigMappingTest.java
new file mode 100644
index 00000000000000..d67d0f2be9fc5b
--- /dev/null
+++ b/core/test-extension/deployment/src/test/java/io/quarkus/extest/ConfigMappingTest.java
@@ -0,0 +1,40 @@
+package io.quarkus.extest;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import javax.inject.Inject;
+
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import io.quarkus.extest.runtime.config.TestMappingBuildTimeRunTime;
+import io.quarkus.extest.runtime.config.TestMappingRunTime;
+import io.quarkus.test.QuarkusUnitTest;
+import io.smallrye.config.SmallRyeConfig;
+
+public class ConfigMappingTest {
+ @RegisterExtension
+ static final QuarkusUnitTest TEST = new QuarkusUnitTest()
+ .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
+ .addAsResource("application.properties"));
+
+ @Inject
+ SmallRyeConfig config;
+
+ @Inject
+ TestMappingBuildTimeRunTime mappingBuildTimeRunTime;
+ @Inject
+ TestMappingRunTime mappingRunTime;
+
+ @Test
+ void mappingBuildTimeRunTime() {
+ assertEquals("value", mappingBuildTimeRunTime.value());
+ }
+
+ @Test
+ void mappingRunTime() {
+ assertEquals("value", mappingBuildTimeRunTime.value());
+ }
+}
diff --git a/core/test-extension/deployment/src/test/resources/build-time-config-test.properties b/core/test-extension/deployment/src/test/resources/build-time-config-test.properties
deleted file mode 100644
index a07978c99967c9..00000000000000
--- a/core/test-extension/deployment/src/test/resources/build-time-config-test.properties
+++ /dev/null
@@ -1,137 +0,0 @@
-# Log settings
-# log level in lower case for testing
-quarkus.log.level=info
-quarkus.log.file.enable=true
-quarkus.log.file.level=INFO
-quarkus.log.file.format=%d{HH:mm:ss} %-5p [%c{2.}]] (%t) %s%e%n
-
-# Resource path to DSAPublicKey base64 encoded bytes
-quarkus.root.dsa-key-location=/DSAPublicKey.encoded
-
-# Have the TestProcessor validate the build time configuration below
-quarkus.root.validate-build-config=true
-
-
-### Configuration settings for the TestBuildTimeConfig config root
-quarkus.bt.bt-string-opt=btStringOptValue
-quarkus.bt.bt-sbv=StringBasedValue
-# This is not set so that we should get the @ConfigItem defaultValue
-#quarkus.bt.bt-sbv-with-default=StringBasedValue
-quarkus.bt.all-values.oov=configPart1+configPart2
-quarkus.bt.all-values.ovo=configPart1+configPart2
-# This is not set so that we should get the @ConfigItem defaultValue
-#quarkus.bt.bt-oov-with-default=ObjectOfValue
-quarkus.bt.all-values.long-primitive=1234567891
-quarkus.bt.all-values.double-primitive=3.1415926535897932384
-quarkus.bt.all-values.long-value=1234567892
-quarkus.bt.all-values.opt-long-value=1234567893
-quarkus.bt.all-values.opt-double-value=3.1415926535897932384
-quarkus.bt.all-values.optional-long-value=1234567894
-quarkus.bt.all-values.nested-config-map.key1.nested-value=value1
-quarkus.bt.all-values.nested-config-map.key1.oov=value1.1+value1.2
-quarkus.bt.all-values.nested-config-map.key2.nested-value=value2
-quarkus.bt.all-values.nested-config-map.key2.oov=value2.1+value2.2
-quarkus.bt.all-values.string-list=value1,value2
-quarkus.bt.all-values.long-list=1,2,3
-
-### Duplicate settings for the TestBuildAndRunTimeConfig. May be able to drop if ConfigRoot inheritance is added
-quarkus.btrt.bt-string-opt=btStringOptValue
-quarkus.btrt.bt-sbv=StringBasedValue
-quarkus.btrt.all-values.oov=configPart1+configPart2
-quarkus.btrt.all-values.ovo=configPart1+configPart2
-quarkus.btrt.all-values.long-primitive=1234567891
-quarkus.btrt.all-values.double-primitive=3.1415926535897932384
-quarkus.btrt.all-values.long-value=1234567892
-quarkus.btrt.all-values.opt-long-value=1234567893
-quarkus.btrt.all-values.opt-double-value=3.1415926535897932384
-quarkus.btrt.all-values.optional-long-value=1234567894
-quarkus.btrt.all-values.nested-config-map.key1.nested-value=value1
-quarkus.btrt.all-values.nested-config-map.key1.oov=value1.1+value1.2
-quarkus.btrt.all-values.nested-config-map.key2.nested-value=value2
-quarkus.btrt.all-values.nested-config-map.key2.oov=value2.1+value2.2
-quarkus.btrt.all-values.string-list=value1,value2
-quarkus.btrt.all-values.long-list=1,2,3
-# The expansion value is not available in runtime so we need to set it directly.
-quarkus.btrt.all-values.expanded-default=1234
-
-### Configuration settings for the TestRunTimeConfig config root
-quarkus.rt.rt-string-opt=rtStringOptValue
-quarkus.rt.rt-string-opt-with-default=rtStringOptWithDefaultValue
-quarkus.rt.all-values.oov=configPart1+configPart2
-quarkus.rt.all-values.ovo=configPart1+configPart2
-quarkus.rt.all-values.long-primitive=12345678911
-quarkus.rt.all-values.double-primitive=3.1415926535897932384
-quarkus.rt.all-values.long-value=12345678921
-quarkus.rt.all-values.opt-long-value=12345678931
-quarkus.rt.all-values.opt-double-value=3.1415926535897932384
-quarkus.rt.all-values.optional-long-value=12345678941
-quarkus.rt.all-values.nested-config-map.key1.nested-value=value1
-quarkus.rt.all-values.nested-config-map.key1.oov=value1.1+value1.2
-quarkus.rt.all-values.nested-config-map.key2.nested-value=value2
-quarkus.rt.all-values.nested-config-map.key2.oov=value2.1+value2.2
-quarkus.rt.all-values.string-list=value1,value2
-quarkus.rt.all-values.long-list=1,2,3
-# A nested map of properties
-quarkus.rt.all-values.string-map.key1=value1
-quarkus.rt.all-values.string-map.key2=value2
-quarkus.rt.all-values.string-map.key3=value3
-# And list form
-quarkus.rt.all-values.string-list-map.key1=value1,value2,value3
-quarkus.rt.all-values.string-list-map.key2=value4,value5
-quarkus.rt.all-values.string-list-map.key3=value6
-# A root map of properties
-quarkus.rt.string-map.key1=value1
-quarkus.rt.string-map.key2=value2
-quarkus.rt.string-map.key3=value3
-# And list form
-quarkus.rt.string-list-map.key1=value1
-quarkus.rt.string-list-map.key2=value2,value3
-quarkus.rt.string-list-map.key3=value4,value5,value6
-
-### run time configuration using enhanced converters
-quarkus.rt.my-enum=enum-two
-quarkus.rt.my-enums=enum-one,enum-two
-quarkus.rt.my-optional-enums=optional
-quarkus.rt.no-hyphenate-first-enum=ENUM_ONE
-quarkus.rt.no-hyphenate-second-enum=Enum_Two
-quarkus.rt.primitive-boolean=YES
-quarkus.rt.object-boolean=NO
-quarkus.rt.primitive-integer=two
-quarkus.rt.object-integer=nine
-quarkus.rt.one-to-nine=one,two,three,four,five,six,seven,eight,nine
-quarkus.rt.map-of-numbers.key1=one
-quarkus.rt.map-of-numbers.key2=two
-
-### map configurations
-quarkus.rt.leaf-map.key.first=first-key-value
-quarkus.rt.leaf-map.key.second=second-key-value
-quarkus.rt.config-group-map.key.group.nested-value=value
-quarkus.rt.config-group-map.key.group.oov=value2.1+value2.2
-
-### build time and run time configuration using enhanced converters
-quarkus.btrt.map-of-numbers.key1=one
-quarkus.btrt.map-of-numbers.key2=two
-quarkus.btrt.my-enum=optional
-quarkus.btrt.my-enums=optional,enum-one,enum-two
-
-### anonymous root property
-quarkus.test-property=foo
-
-### map of map of strings
-quarkus.rt.map-map.outer-key.inner-key=1234
-quarkus.btrt.map-map.outer-key.inner-key=1234
-quarkus.bt.map-map.outer-key.inner-key=1234
-
-# Test config root with "RuntimeConfig" suffix
-quarkus.foo.bar=huhu
-
-### named map with profiles
-quarkus.btrt.map-map.main-profile.property=1234
-%test.quarkus.btrt.map-map.test-profile.property=5678
-
-### ordinal and default values source
-config_ordinal=1000
-my.prop=1234
-%prod.my.prop=1234
-%dev.my.prop=5678
-%test.my.prop=1234
\ No newline at end of file
diff --git a/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/config/TestMappingBuildTime.java b/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/config/TestMappingBuildTime.java
new file mode 100644
index 00000000000000..5872a54f6d0a23
--- /dev/null
+++ b/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/config/TestMappingBuildTime.java
@@ -0,0 +1,44 @@
+package io.quarkus.extest.runtime.config;
+
+import java.util.List;
+import java.util.Optional;
+
+import io.quarkus.runtime.annotations.ConfigPhase;
+import io.quarkus.runtime.annotations.ConfigRoot;
+import io.smallrye.config.ConfigMapping;
+
+@ConfigMapping(prefix = "quarkus.mapping.bt")
+@ConfigRoot(phase = ConfigPhase.BUILD_TIME)
+public interface TestMappingBuildTime {
+ /**
+ * A String value.
+ */
+ String value();
+
+ /**
+ * A nested Group.
+ */
+ Group group();
+
+ /**
+ * An Optional missing Group.
+ */
+ Optional missing();
+
+ /**
+ * An Optional present Group.
+ */
+ Optional present();
+
+ /**
+ * A List of Groups.
+ */
+ List groups();
+
+ interface Group {
+ /**
+ * A Group value.
+ */
+ String value();
+ }
+}
diff --git a/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/config/TestMappingBuildTimeRunTime.java b/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/config/TestMappingBuildTimeRunTime.java
new file mode 100644
index 00000000000000..781a017516036f
--- /dev/null
+++ b/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/config/TestMappingBuildTimeRunTime.java
@@ -0,0 +1,26 @@
+package io.quarkus.extest.runtime.config;
+
+import io.quarkus.runtime.annotations.ConfigPhase;
+import io.quarkus.runtime.annotations.ConfigRoot;
+import io.smallrye.config.ConfigMapping;
+
+@ConfigMapping(prefix = "quarkus.mapping.btrt")
+@ConfigRoot(phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED)
+public interface TestMappingBuildTimeRunTime {
+ /**
+ * A String value
+ */
+ String value();
+
+ /**
+ * A nested Group.
+ */
+ Group group();
+
+ interface Group {
+ /**
+ * A Group value.
+ */
+ String value();
+ }
+}
diff --git a/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/config/TestMappingRunTime.java b/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/config/TestMappingRunTime.java
new file mode 100644
index 00000000000000..39d3fdabccd780
--- /dev/null
+++ b/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/config/TestMappingRunTime.java
@@ -0,0 +1,26 @@
+package io.quarkus.extest.runtime.config;
+
+import io.quarkus.runtime.annotations.ConfigPhase;
+import io.quarkus.runtime.annotations.ConfigRoot;
+import io.smallrye.config.ConfigMapping;
+
+@ConfigMapping(prefix = "quarkus.mapping.rt")
+@ConfigRoot(phase = ConfigPhase.RUN_TIME)
+public interface TestMappingRunTime {
+ /**
+ * A String value.
+ */
+ String value();
+
+ /**
+ * A nested Group.
+ */
+ Group group();
+
+ interface Group {
+ /**
+ * A Group value.
+ */
+ String value();
+ }
+}