diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml
new file mode 100644
index 00000000000000..d820426cb4d410
--- /dev/null
+++ b/.mvn/extensions.xml
@@ -0,0 +1,13 @@
+
+
+
+ org.srcdeps.mvn
+ srcdeps-maven-local-repository
+ 4.0.0
+
+
+ org.srcdeps.mvn
+ srcdeps-maven-enforcer
+ 4.0.0
+
+
diff --git a/bom/application/pom.xml b/bom/application/pom.xml
index 89774fc3ea5d75..8f74995ccce605 100644
--- a/bom/application/pom.xml
+++ b/bom/application/pom.xml
@@ -17,7 +17,7 @@
1.67
1.0.2
2.2.2.Final
- 4.5.8.Final
+ 4.6.0-SNAPSHOT
0.31.0
0.4.1
0.2.3
@@ -31,14 +31,14 @@
1.4.3
1.6.1
0.22.0
- 1.4
+ 2.0
2.3
1.0.1
1.3.3
1.0.1
1.4.1
1.5.0
- 1.9.3
+ 2.0.0-SNAPSHOT
2.2.5
2.4.4
2.0.16
diff --git a/build-parent/pom.xml b/build-parent/pom.xml
index 295589ece619c1..583e30b245375d 100644
--- a/build-parent/pom.xml
+++ b/build-parent/pom.xml
@@ -60,7 +60,7 @@
2.2
- 1.4
+ 2.0
2.3.2
2.1.1
1.0
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 49a77b3ea63615..69f846870cac30 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
@@ -674,7 +674,7 @@ private Converter> getConverter(SmallRyeConfig config, Field field, ConverterT
throw toError(e);
}
} else {
- converter = config.getConverter(leaf.getLeafType());
+ converter = config.requireConverter(leaf.getLeafType());
}
} else if (valueType instanceof LowerBoundCheckOf) {
// todo: add in bounds checker
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/configuration/DefaultValuesConfigurationSource.java b/core/deployment/src/main/java/io/quarkus/deployment/configuration/DefaultValuesConfigurationSource.java
index 289f7d4d74a70d..59df69b94ed5e3 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/configuration/DefaultValuesConfigurationSource.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/configuration/DefaultValuesConfigurationSource.java
@@ -2,6 +2,7 @@
import java.util.Collections;
import java.util.Map;
+import java.util.Set;
import org.eclipse.microprofile.config.spi.ConfigSource;
@@ -23,6 +24,10 @@ public Map getProperties() {
return Collections.emptyMap();
}
+ public Set getPropertyNames() {
+ return Collections.emptySet();
+ }
+
public String getValue(final String propertyName) {
if (!propertyName.startsWith("quarkus.")) {
return null;
diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/AbstractRawDefaultConfigSource.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/AbstractRawDefaultConfigSource.java
index 3b1d418c9a72bb..8f5ded92781ef5 100644
--- a/core/runtime/src/main/java/io/quarkus/runtime/configuration/AbstractRawDefaultConfigSource.java
+++ b/core/runtime/src/main/java/io/quarkus/runtime/configuration/AbstractRawDefaultConfigSource.java
@@ -3,6 +3,7 @@
import java.io.Serializable;
import java.util.Collections;
import java.util.Map;
+import java.util.Set;
import org.eclipse.microprofile.config.spi.ConfigSource;
@@ -19,6 +20,10 @@ public Map getProperties() {
return Collections.emptyMap();
}
+ public Set getPropertyNames() {
+ return Collections.emptySet();
+ }
+
public String getValue(final String propertyName) {
return getValue(new NameIterator(propertyName));
}
diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/ApplicationPropertiesConfigSource.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/ApplicationPropertiesConfigSource.java
index d8415f850e0bd0..155c16db826c69 100644
--- a/core/runtime/src/main/java/io/quarkus/runtime/configuration/ApplicationPropertiesConfigSource.java
+++ b/core/runtime/src/main/java/io/quarkus/runtime/configuration/ApplicationPropertiesConfigSource.java
@@ -25,16 +25,11 @@ public abstract class ApplicationPropertiesConfigSource extends PropertiesConfig
private static final long serialVersionUID = -4694780118527396798L;
static final String APPLICATION_PROPERTIES = "application.properties";
- static final String MP_PROPERTIES = "META-INF/microprofile-config.properties";
ApplicationPropertiesConfigSource(InputStream is, int ordinal) {
super(readProperties(is), APPLICATION_PROPERTIES, ordinal);
}
- ApplicationPropertiesConfigSource(InputStream is, String nm, int ordinal) {
- super(readProperties(is), nm, ordinal);
- }
-
private static Map readProperties(final InputStream is) {
if (is == null) {
return Collections.emptyMap();
@@ -72,29 +67,6 @@ private static InputStream openStream() {
}
}
- /**
- * Config that makes sure that the MP config in the application takes precedence over any other on the class path
- */
- public static final class MpConfigInJar extends ApplicationPropertiesConfigSource {
- public MpConfigInJar() {
- super(openStream(), MP_PROPERTIES, 240);
- }
-
- private static InputStream openStream() {
- ClassLoader cl = Thread.currentThread().getContextClassLoader();
- if (cl == null) {
- cl = ApplicationPropertiesConfigSource.class.getClassLoader();
- }
- InputStream is;
- if (cl == null) {
- is = ClassLoader.getSystemResourceAsStream(MP_PROPERTIES);
- } else {
- is = cl.getResourceAsStream(MP_PROPERTIES);
- }
- return is;
- }
- }
-
public static final class InFileSystem extends ApplicationPropertiesConfigSource {
public InFileSystem() {
super(openStream(), 260);
diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigInstantiator.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigInstantiator.java
index 96b763be8d38cd..7215b796468dd0 100644
--- a/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigInstantiator.java
+++ b/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigInstantiator.java
@@ -118,7 +118,7 @@ private static Converter> getConverterFor(Type type) {
} else if (rawType == List.class) {
return Converters.newCollectionConverter(getConverterFor(typeOfParameter(type, 0)), ArrayList::new);
} else {
- return config.getConverter(rawTypeOf(type));
+ return config.requireConverter(rawTypeOf(type));
}
}
diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigUtils.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigUtils.java
index 273525ababad29..f402bd266f2c5a 100644
--- a/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigUtils.java
+++ b/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigUtils.java
@@ -1,5 +1,8 @@
package io.quarkus.runtime.configuration;
+import static io.smallrye.config.SmallRyeConfigBuilder.META_INF_MICROPROFILE_CONFIG_PROPERTIES;
+import static io.smallrye.config.SmallRyeConfigBuilder.WEB_INF_MICROPROFILE_CONFIG_PROPERTIES;
+
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
@@ -31,6 +34,8 @@
import org.eclipse.microprofile.config.spi.ConfigSourceProvider;
import org.jboss.logging.Logger;
+import io.smallrye.config.ProfileConfigSourceInterceptor;
+import io.smallrye.config.PropertiesConfigSourceProvider;
import io.smallrye.config.SmallRyeConfigBuilder;
/**
@@ -69,22 +74,18 @@ public static SmallRyeConfigBuilder configBuilder(final boolean runTime, final b
final SmallRyeConfigBuilder builder = new SmallRyeConfigBuilder();
final ApplicationPropertiesConfigSource.InFileSystem inFileSystem = new ApplicationPropertiesConfigSource.InFileSystem();
final ApplicationPropertiesConfigSource.InJar inJar = new ApplicationPropertiesConfigSource.InJar();
- final ApplicationPropertiesConfigSource.MpConfigInJar mpConfig = new ApplicationPropertiesConfigSource.MpConfigInJar();
- builder.withSources(inFileSystem, inJar, mpConfig, new DotEnvConfigSource());
- builder.withProfile(ProfileManager.getActiveProfile());
+ builder.withSources(inFileSystem, inJar, new DotEnvConfigSource());
+ builder.withDefaultValue(ProfileConfigSourceInterceptor.SMALLRYE_PROFILE, ProfileManager.getActiveProfile());
builder.addDefaultInterceptors();
final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (runTime) {
builder.addDefaultSources();
} else {
final List sources = new ArrayList<>();
- sources.addAll(
- new QuarkusPropertiesConfigSourceProvider("META-INF/microprofile-config.properties", true, classLoader)
- .getConfigSources(classLoader));
- // required by spec...
- sources.addAll(
- new QuarkusPropertiesConfigSourceProvider("WEB-INF/classes/META-INF/microprofile-config.properties", true,
- classLoader).getConfigSources(classLoader));
+ sources.addAll(new PropertiesConfigSourceProvider(META_INF_MICROPROFILE_CONFIG_PROPERTIES, classLoader)
+ .getConfigSources(classLoader));
+ sources.addAll(new PropertiesConfigSourceProvider(WEB_INF_MICROPROFILE_CONFIG_PROPERTIES, classLoader)
+ .getConfigSources(classLoader));
sources.add(new EnvConfigSource());
sources.add(new SysPropConfigSource());
builder.withSources(sources);
@@ -140,6 +141,10 @@ public Map getProperties() {
return Collections.emptyMap();
}
+ public Set getPropertyNames() {
+ return Collections.emptySet();
+ }
+
public String getValue(final String propertyName) {
String val = cache.get(propertyName);
if (val != null) {
@@ -213,6 +218,11 @@ public Map getProperties() {
return output;
}
+ @Override
+ public Set getPropertyNames() {
+ return getProperties().keySet();
+ }
+
public String getValue(final String propertyName) {
return System.getProperty(propertyName);
}
diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/QuarkusPropertiesConfigSourceProvider.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/QuarkusPropertiesConfigSourceProvider.java
deleted file mode 100644
index f5b7e5872c9010..00000000000000
--- a/core/runtime/src/main/java/io/quarkus/runtime/configuration/QuarkusPropertiesConfigSourceProvider.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package io.quarkus.runtime.configuration;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.UncheckedIOException;
-import java.net.URL;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-
-import org.eclipse.microprofile.config.spi.ConfigSource;
-import org.eclipse.microprofile.config.spi.ConfigSourceProvider;
-
-import io.quarkus.runtime.util.ClassPathUtils;
-import io.smallrye.config.common.MapBackedConfigSource;
-import io.smallrye.config.common.utils.ConfigSourceUtil;
-
-public class QuarkusPropertiesConfigSourceProvider implements ConfigSourceProvider {
-
- private List configSources = new ArrayList<>();
-
- public QuarkusPropertiesConfigSourceProvider(String propertyFileName, boolean optional, ClassLoader classLoader) {
- try {
- Enumeration propertyFileUrls = classLoader.getResources(propertyFileName);
-
- if (!optional && !propertyFileUrls.hasMoreElements()) {
- throw new IllegalStateException(propertyFileName + " wasn't found.");
- }
-
- while (propertyFileUrls.hasMoreElements()) {
- URL propertyFileUrl = propertyFileUrls.nextElement();
- configSources.add(new PropertiesConfigSource(propertyFileUrl));
- }
- } catch (IOException ioe) {
- throw new IllegalStateException("problem while loading microprofile-config.properties files", ioe);
- }
-
- }
-
- @Override
- public List getConfigSources(ClassLoader forClassLoader) {
- return configSources;
- }
-
- private static class PropertiesConfigSource extends MapBackedConfigSource {
- private static final long serialVersionUID = 1866835565147832432L;
-
- private static final String NAME_PREFIX = "PropertiesConfigSource[source=";
-
- /**
- * Construct a new instance
- *
- * @param url a property file location
- * @throws IOException if an error occurred when reading from the input stream
- */
- public PropertiesConfigSource(URL url) throws IOException {
- super(NAME_PREFIX + url.toString() + "]", urlToMap(url));
- }
-
- public PropertiesConfigSource(Properties properties, String source) {
- super(NAME_PREFIX + source + "]", ConfigSourceUtil.propertiesToMap(properties));
- }
-
- public PropertiesConfigSource(Map properties, String source, int ordinal) {
- super(NAME_PREFIX + source + "]", properties, ordinal);
- }
- }
-
- private static Map urlToMap(URL url) throws IOException {
- final Properties props = new Properties();
- ClassPathUtils.consumeStream(url, is -> {
- try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
- props.load(reader);
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- });
- return ConfigSourceUtil.propertiesToMap(props);
- }
-}
diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/Substitutions.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/Substitutions.java
index 3a35bda308015b..c78282affeb933 100644
--- a/core/runtime/src/main/java/io/quarkus/runtime/configuration/Substitutions.java
+++ b/core/runtime/src/main/java/io/quarkus/runtime/configuration/Substitutions.java
@@ -94,4 +94,21 @@ public byte[] getClassBytes() {
return null;
}
}
+
+ @TargetClass(className = "io.smallrye.config.ConfigMappingClass")
+ static final class Target_ConfigMappingClass {
+ @Alias
+ static ClassValue cv = null;
+
+ // ClassValue is substituted by a regular ConcurrentHashMap - java.lang.ClassValue.get(JavaLangSubstitutions.java:514)
+ @Substitute
+ public static Target_ConfigMappingClass getConfigurationClass(Class> classType) {
+ Assert.checkNotNullParam("classType", classType);
+ try {
+ return cv.get(classType);
+ } catch (NullPointerException e) {
+ return null;
+ }
+ }
+ }
}
diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ConfigBuildStep.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ConfigBuildStep.java
index bdf964b77f2426..6ba2d7049c6eb0 100644
--- a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ConfigBuildStep.java
+++ b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ConfigBuildStep.java
@@ -1,28 +1,36 @@
package io.quarkus.arc.deployment;
+import static io.quarkus.arc.processor.BuildExtension.Key.INJECTION_POINTS;
import static io.quarkus.deployment.annotations.ExecutionTime.RUNTIME_INIT;
import static io.smallrye.config.ConfigMappings.ConfigMappingWithPrefix.configMappingWithPrefix;
-import static java.util.stream.Collectors.groupingBy;
-import static java.util.stream.Collectors.mapping;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;
+import static org.jboss.jandex.AnnotationInstance.create;
+import static org.jboss.jandex.AnnotationTarget.Kind.CLASS;
+import static org.jboss.jandex.AnnotationTarget.Kind.FIELD;
+import static org.jboss.jandex.AnnotationTarget.Kind.METHOD_PARAMETER;
+import static org.jboss.jandex.AnnotationValue.createStringValue;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
-import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import java.util.function.Supplier;
import java.util.stream.Stream;
import javax.enterprise.context.Dependent;
import javax.enterprise.inject.CreationException;
+import org.eclipse.microprofile.config.ConfigValue;
+import org.eclipse.microprofile.config.inject.ConfigProperties;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationTarget;
import org.jboss.jandex.AnnotationValue;
import org.jboss.jandex.ClassInfo;
+import org.jboss.jandex.ClassType;
import org.jboss.jandex.DotName;
import org.jboss.jandex.FieldInfo;
import org.jboss.jandex.MethodInfo;
@@ -30,13 +38,14 @@
import org.jboss.jandex.Type.Kind;
import io.quarkus.arc.deployment.BeanRegistrationPhaseBuildItem.BeanConfiguratorBuildItem;
+import io.quarkus.arc.processor.AnnotationsTransformer;
import io.quarkus.arc.processor.BeanRegistrar;
-import io.quarkus.arc.processor.BuildExtension;
import io.quarkus.arc.processor.DotNames;
import io.quarkus.arc.processor.InjectionPointInfo;
import io.quarkus.arc.runtime.ConfigBeanCreator;
import io.quarkus.arc.runtime.ConfigMappingCreator;
import io.quarkus.arc.runtime.ConfigRecorder;
+import io.quarkus.arc.runtime.ConfigRecorder.ConfigValidationMetadata;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.Record;
@@ -59,14 +68,20 @@
*/
public class ConfigBuildStep {
- private static final DotName CONFIG_PROPERTY_NAME = DotName.createSimple(ConfigProperty.class.getName());
+ private static final DotName MP_CONFIG_PROPERTY_NAME = DotName.createSimple(ConfigProperty.class.getName());
+ private static final DotName MP_CONFIG_PROPERTIES_NAME = DotName.createSimple(ConfigProperties.class.getName());
+ private static final DotName MP_CONFIG_VALUE_NAME = DotName.createSimple(ConfigValue.class.getName());
+
private static final DotName CONFIG_MAPPING_NAME = DotName.createSimple(ConfigMapping.class.getName());
private static final DotName SET_NAME = DotName.createSimple(Set.class.getName());
private static final DotName LIST_NAME = DotName.createSimple(List.class.getName());
+ private static final DotName SUPPLIER_NAME = DotName.createSimple(Supplier.class.getName());
+ private static final DotName CONFIG_VALUE_NAME = DotName.createSimple(io.smallrye.config.ConfigValue.class.getName());
@BuildStep
- AdditionalBeanBuildItem bean() {
- return new AdditionalBeanBuildItem(ConfigProducer.class);
+ public void additionalBeans(BuildProducer additionalBeans) {
+ additionalBeans.produce(new AdditionalBeanBuildItem(ConfigProducer.class));
+ additionalBeans.produce(new AdditionalBeanBuildItem(ConfigProperties.class));
}
@BuildStep
@@ -77,13 +92,13 @@ void analyzeConfigPropertyInjectionPoints(BeanRegistrationPhaseBuildItem beanReg
Set customBeanTypes = new HashSet<>();
- for (InjectionPointInfo injectionPoint : beanRegistrationPhase.getContext().get(BuildExtension.Key.INJECTION_POINTS)) {
+ for (InjectionPointInfo injectionPoint : beanRegistrationPhase.getContext().get(INJECTION_POINTS)) {
if (injectionPoint.hasDefaultedQualifier()) {
// Defaulted qualifier means no @ConfigProperty
continue;
}
- AnnotationInstance configProperty = injectionPoint.getRequiredQualifier(CONFIG_PROPERTY_NAME);
+ AnnotationInstance configProperty = injectionPoint.getRequiredQualifier(MP_CONFIG_PROPERTY_NAME);
if (configProperty != null) {
AnnotationValue nameValue = configProperty.value("name");
AnnotationValue defaultValue = configProperty.value("defaultValue");
@@ -113,16 +128,22 @@ void analyzeConfigPropertyInjectionPoints(BeanRegistrationPhaseBuildItem beanReg
if (DotNames.OPTIONAL.equals(requiredType.name())
|| DotNames.OPTIONAL_INT.equals(requiredType.name())
|| DotNames.OPTIONAL_LONG.equals(requiredType.name())
- || DotNames.OPTIONAL_DOUBLE.equals(requiredType.name())) {
- // Never validate Optional values
+ || DotNames.OPTIONAL_DOUBLE.equals(requiredType.name())
+ || DotNames.PROVIDER.equals(requiredType.name())
+ || SUPPLIER_NAME.equals(requiredType.name())
+ || CONFIG_VALUE_NAME.equals(requiredType.name())
+ || MP_CONFIG_VALUE_NAME.equals(requiredType.name())) {
+ // Never validate container objects
continue;
}
- if (defaultValue != null && !ConfigProperty.UNCONFIGURED_VALUE.equals(defaultValue.asString())) {
- // No need to validate properties with default values
- continue;
+
+ String propertyDefaultValue = null;
+ if (defaultValue != null && (ConfigProperty.UNCONFIGURED_VALUE.equals(defaultValue.asString())
+ || !"".equals(defaultValue.asString()))) {
+ propertyDefaultValue = defaultValue.asString();
}
- configProperties.produce(new ConfigPropertyBuildItem(propertyName, requiredType));
+ configProperties.produce(new ConfigPropertyBuildItem(propertyName, requiredType, propertyDefaultValue));
}
}
@@ -136,7 +157,7 @@ void analyzeConfigPropertyInjectionPoints(BeanRegistrationPhaseBuildItem beanReg
.creator(ConfigBeanCreator.class)
.providerType(type)
.types(type)
- .qualifiers(AnnotationInstance.create(CONFIG_PROPERTY_NAME, null, Collections.emptyList()))
+ .qualifiers(create(MP_CONFIG_PROPERTY_NAME, null, Collections.emptyList()))
.param("requiredType", type.name().toString())));
}
}
@@ -156,10 +177,14 @@ void validateConfigProperties(ConfigRecorder recorder, List> propNamesToClasses = configProperties.stream().collect(
- groupingBy(ConfigPropertyBuildItem::getPropertyName,
- mapping(c -> c.getPropertyType().name().toString(), toSet())));
- recorder.validateConfigProperties(propNamesToClasses);
+ Set propertiesToValidate = new HashSet<>();
+ for (ConfigPropertyBuildItem configProperty : configProperties) {
+ propertiesToValidate.add(new ConfigValidationMetadata(configProperty.getPropertyName(),
+ configProperty.getPropertyType().name().toString(),
+ configProperty.getDefaultValue()));
+ }
+
+ recorder.validateConfigProperties(propertiesToValidate);
}
@BuildStep
@@ -188,6 +213,25 @@ public void register(RegistrationContext context) {
});
}
+ @BuildStep
+ AnnotationsTransformerBuildItem vetoMPConfigProperties() {
+ return new AnnotationsTransformerBuildItem(new AnnotationsTransformer() {
+ public boolean appliesTo(org.jboss.jandex.AnnotationTarget.Kind kind) {
+ return CLASS.equals(kind);
+ }
+
+ public void transform(TransformationContext context) {
+ if (context.getAnnotations().stream()
+ .anyMatch(annotation -> annotation.name().equals(MP_CONFIG_PROPERTIES_NAME))) {
+ context.transform()
+ .add(DotNames.VETOED)
+ .add(DotNames.UNREMOVABLE)
+ .done();
+ }
+ }
+ });
+ }
+
@BuildStep
void generateConfigMappings(
CombinedIndexBuildItem combinedIndex,
@@ -197,14 +241,37 @@ void generateConfigMappings(
BuildProducer configMappings,
BuildProducer beanConfigurators) {
- for (AnnotationInstance instance : combinedIndex.getIndex().getAnnotations(CONFIG_MAPPING_NAME)) {
+ List mappingAnnotations = new ArrayList<>();
+ mappingAnnotations.addAll(combinedIndex.getIndex().getAnnotations(CONFIG_MAPPING_NAME));
+ mappingAnnotations.addAll(combinedIndex.getIndex().getAnnotations(MP_CONFIG_PROPERTIES_NAME));
+
+ for (AnnotationInstance instance : mappingAnnotations) {
AnnotationTarget target = instance.target();
- if (!target.kind().equals(AnnotationTarget.Kind.CLASS)) {
+ AnnotationValue annotationPrefix = instance.value("prefix");
+
+ if (target.kind().equals(FIELD)) {
+ if (annotationPrefix != null && !annotationPrefix.asString().equals(ConfigProperties.UNCONFIGURED_PREFIX)) {
+ configMappings.produce(
+ new ConfigMappingBuildItem(toClass(target.asField().type().name()), annotationPrefix.asString()));
+ continue;
+ }
+ }
+
+ if (target.kind().equals(METHOD_PARAMETER)) {
+ if (annotationPrefix != null && !annotationPrefix.asString().equals(ConfigProperties.UNCONFIGURED_PREFIX)) {
+ ClassType classType = target.asMethodParameter().method().parameters()
+ .get(target.asMethodParameter().position()).asClassType();
+ configMappings.produce(new ConfigMappingBuildItem(toClass(classType.name()), annotationPrefix.asString()));
+ continue;
+ }
+ }
+
+ if (!target.kind().equals(CLASS)) {
continue;
}
- Class> type = toClass(target.asClass());
- String prefix = Optional.ofNullable(instance.value("prefix")).map(AnnotationValue::asString).orElse("");
+ Class> type = toClass(target.asClass().name());
+ String prefix = Optional.ofNullable(annotationPrefix).map(AnnotationValue::asString).orElse("");
List configMappingsMetadata = ConfigMappingLoader.getConfigMappingsMetadata(type);
configMappingsMetadata.forEach(mappingMetadata -> {
@@ -218,12 +285,20 @@ void generateConfigMappings(
configMappings.produce(new ConfigMappingBuildItem(type, prefix));
+ List qualifiers = new ArrayList<>();
+ if (instance.name().equals(MP_CONFIG_PROPERTIES_NAME)) {
+ qualifiers.add(
+ create(MP_CONFIG_PROPERTIES_NAME, null, new AnnotationValue[] { createStringValue("prefix", prefix) }));
+ }
+
beanConfigurators.produce(new BeanConfiguratorBuildItem(
beanRegistrationPhase.getContext()
.configure(type)
.types(type)
+ .qualifiers(qualifiers.toArray(new AnnotationInstance[] {}))
.creator(ConfigMappingCreator.class)
- .param("type", type)));
+ .param("type", type)
+ .param("prefix", prefix)));
}
}
@@ -244,13 +319,12 @@ void registerConfigMappings(
.collect(toSet()));
}
- private static Class> toClass(ClassInfo classInfo) {
- String className = classInfo.name().toString();
+ private static Class> toClass(DotName dotName) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
try {
- return classLoader.loadClass(className);
+ return classLoader.loadClass(dotName.toString());
} catch (ClassNotFoundException e) {
- throw new IllegalStateException("The class (" + className + ") cannot be created during deployment.", e);
+ throw new IllegalStateException("The class (" + dotName.toString() + ") cannot be created during deployment.", e);
}
}
@@ -285,7 +359,9 @@ private boolean isHandledByProducers(Type type) {
DotNames.DOUBLE.equals(type.name()) ||
DotNames.SHORT.equals(type.name()) ||
DotNames.BYTE.equals(type.name()) ||
- DotNames.CHARACTER.equals(type.name());
+ DotNames.CHARACTER.equals(type.name()) ||
+ SUPPLIER_NAME.equals(type.name()) ||
+ CONFIG_VALUE_NAME.equals(type.name()) ||
+ MP_CONFIG_VALUE_NAME.equals(type.name());
}
-
}
diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ConfigPropertyBuildItem.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ConfigPropertyBuildItem.java
index 14003a02df1c51..ad5fef88ab6cf6 100644
--- a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ConfigPropertyBuildItem.java
+++ b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ConfigPropertyBuildItem.java
@@ -8,14 +8,14 @@
* Represents a mandatory config property that needs to be validated at runtime.
*/
public final class ConfigPropertyBuildItem extends MultiBuildItem {
-
private final String propertyName;
-
private final Type propertyType;
+ private final String defaultValue;
- public ConfigPropertyBuildItem(String propertyName, Type propertyType) {
+ public ConfigPropertyBuildItem(final String propertyName, final Type propertyType, final String defaultValue) {
this.propertyName = propertyName;
this.propertyType = propertyType;
+ this.defaultValue = defaultValue;
}
public String getPropertyName() {
@@ -26,4 +26,7 @@ public Type getPropertyType() {
return propertyType;
}
+ public String getDefaultValue() {
+ return defaultValue;
+ }
}
diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/configproperties/ClassConfigPropertiesUtil.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/configproperties/ClassConfigPropertiesUtil.java
index 551cc2acf9383d..a55a551ac27574 100644
--- a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/configproperties/ClassConfigPropertiesUtil.java
+++ b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/configproperties/ClassConfigPropertiesUtil.java
@@ -382,7 +382,8 @@ private static ResultHandle populateConfigObject(ClassLoader classLoader, ClassI
for (ConfigPropertyBuildItemCandidate candidate : configPropertyBuildItemCandidates) {
configProperties
- .produce(new ConfigPropertyBuildItem(candidate.getConfigPropertyName(), candidate.getConfigPropertyType()));
+ .produce(new ConfigPropertyBuildItem(candidate.getConfigPropertyName(), candidate.getConfigPropertyType(),
+ null));
}
return configObject;
diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/configproperties/DotNames.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/configproperties/DotNames.java
index f2c543998c4b13..64afa862b880ab 100644
--- a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/configproperties/DotNames.java
+++ b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/configproperties/DotNames.java
@@ -24,6 +24,8 @@ private DotNames() {
static final DotName SET = DotName.createSimple(Set.class.getName());
static final DotName COLLECTION = DotName.createSimple(Collection.class.getName());
static final DotName ENUM = DotName.createSimple(Enum.class.getName());
+ static final DotName MP_CONFIG_PROPERTIES = DotName
+ .createSimple(org.eclipse.microprofile.config.inject.ConfigProperties.class.getName());
static final DotName CONFIG_PROPERTIES = DotName.createSimple(ConfigProperties.class.getName());
static final DotName CONFIG_PREFIX = DotName.createSimple(ConfigPrefix.class.getName());
static final DotName CONFIG_IGNORE = DotName.createSimple(ConfigIgnore.class.getName());
diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/configproperties/InterfaceConfigPropertiesUtil.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/configproperties/InterfaceConfigPropertiesUtil.java
index bd919b970863cd..2c5cb4288ad68d 100644
--- a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/configproperties/InterfaceConfigPropertiesUtil.java
+++ b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/configproperties/InterfaceConfigPropertiesUtil.java
@@ -237,7 +237,7 @@ private static void generateImplementationForInterfaceConfigPropertiesRec(ClassI
methodCreator.returnValue(value);
if (defaultValueStr == null || ConfigProperty.UNCONFIGURED_VALUE.equals(defaultValueStr)) {
configProperties
- .produce(new ConfigPropertyBuildItem(fullConfigName, returnType));
+ .produce(new ConfigPropertyBuildItem(fullConfigName, returnType, defaultValueStr));
}
}
}
diff --git a/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/config/ConfigPropertiesTest.java b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/config/ConfigPropertiesTest.java
new file mode 100644
index 00000000000000..dd26cfdc5f2c0d
--- /dev/null
+++ b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/config/ConfigPropertiesTest.java
@@ -0,0 +1,168 @@
+package io.quarkus.arc.test.config;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import javax.enterprise.context.Dependent;
+import javax.enterprise.inject.spi.CDI;
+import javax.inject.Inject;
+
+import org.eclipse.microprofile.config.inject.ConfigProperties;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.asset.StringAsset;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import io.quarkus.test.QuarkusUnitTest;
+import io.smallrye.config.ConfigMapping;
+import io.smallrye.config.WithDefault;
+
+public class ConfigPropertiesTest {
+ @RegisterExtension
+ static final QuarkusUnitTest TEST = new QuarkusUnitTest()
+ .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
+ .addAsResource(new StringAsset("server.host=localhost\n" +
+ "server.port=8080\n" +
+ "cloud.host=cloud\n" +
+ "cloud.port=9090\n" +
+ "host=empty\n" +
+ "port=0\n"),
+ "application.properties"));
+
+ @Inject
+ Server server;
+
+ @Test
+ void configMapping() {
+ assertNotNull(server);
+ assertEquals("localhost", server.host());
+ assertEquals(8080, server.port());
+ }
+
+ @Inject
+ Client client;
+
+ @Test
+ void discoveredMapping() {
+ assertNotNull(client);
+ assertEquals("client", client.host());
+ assertEquals(80, client.port());
+ }
+
+ @Inject
+ @ConfigMapping(prefix = "cloud")
+ Server cloud;
+
+ @Test
+ void overridePrefix() {
+ assertNotNull(cloud);
+ assertEquals("cloud", cloud.host());
+ assertEquals(9090, cloud.port());
+ }
+
+ @Inject
+ @ConfigProperties
+ ServerConfigProperties configProperties;
+ @Inject
+ @ConfigProperties(prefix = "cloud")
+ ServerConfigProperties configPropertiesCloud;
+ @Inject
+ @ConfigProperties(prefix = "")
+ ServerConfigProperties configPropertiesEmpty;
+
+ @Test
+ void configProperties() {
+ assertNotNull(configProperties);
+ assertEquals("localhost", configProperties.host);
+ assertEquals(8080, configProperties.port);
+
+ assertNotNull(configPropertiesCloud);
+ assertEquals("cloud", configPropertiesCloud.host);
+ assertEquals(9090, configPropertiesCloud.port);
+
+ assertNotNull(configPropertiesEmpty);
+ assertEquals("empty", configPropertiesEmpty.host);
+ assertEquals(0, configPropertiesEmpty.port);
+ }
+
+ @Test
+ void select() {
+ Server server = CDI.current().select(Server.class).get();
+ assertNotNull(server);
+ assertEquals("localhost", server.host());
+ assertEquals(8080, server.port());
+
+ ServerConfigProperties serverConfigProperties = CDI.current()
+ .select(ServerConfigProperties.class, ConfigProperties.Literal.NO_PREFIX).get();
+ assertNotNull(serverConfigProperties);
+ assertEquals("localhost", serverConfigProperties.host);
+ assertEquals(8080, serverConfigProperties.port);
+
+ ServerConfigProperties cloudConfigProperties = CDI.current()
+ .select(ServerConfigProperties.class, ConfigProperties.Literal.of("cloud")).get();
+ assertNotNull(cloudConfigProperties);
+ assertEquals("cloud", cloudConfigProperties.host);
+ assertEquals(9090, cloudConfigProperties.port);
+ }
+
+ @Inject
+ ConfigMappingBean configMappingBean;
+
+ @Test
+ void overridePrefixBean() {
+ Server cloud = configMappingBean.getCloud();
+ assertEquals("cloud", cloud.host());
+ assertEquals(9090, cloud.port());
+
+ Server client = configMappingBean.getClient();
+ assertEquals("client", client.host());
+ assertEquals(80, client.port());
+ }
+
+ @ConfigMapping(prefix = "server")
+ public interface Server {
+ String host();
+
+ int port();
+ }
+
+ @ConfigMapping(prefix = "client")
+ public interface Client {
+ @WithDefault("client")
+ String host();
+
+ @WithDefault("80")
+ int port();
+ }
+
+ @ConfigProperties(prefix = "server")
+ public static class ServerConfigProperties {
+ public String host;
+ public int port;
+ }
+
+ @Dependent
+ static class ConfigMappingBean {
+ private final Server cloud;
+ private Server client;
+
+ @Inject
+ public ConfigMappingBean(@ConfigMapping(prefix = "cloud") Server cloud) {
+ this.cloud = cloud;
+ }
+
+ public Server getCloud() {
+ return cloud;
+ }
+
+ public Server getClient() {
+ return client;
+ }
+
+ @Inject
+ public void setClient(@ConfigMapping(prefix = "client") final Server client) {
+ this.client = client;
+ }
+ }
+}
diff --git a/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/config/NullConverterTest.java b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/config/NullConverterTest.java
new file mode 100644
index 00000000000000..afd8ecf2f1128f
--- /dev/null
+++ b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/config/NullConverterTest.java
@@ -0,0 +1,49 @@
+package io.quarkus.arc.test.config;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.spi.DeploymentException;
+import javax.inject.Inject;
+
+import org.eclipse.microprofile.config.inject.ConfigProperty;
+import org.eclipse.microprofile.config.spi.Converter;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.asset.StringAsset;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import io.quarkus.test.QuarkusUnitTest;
+
+public class NullConverterTest {
+ @RegisterExtension
+ static final QuarkusUnitTest TEST = new QuarkusUnitTest()
+ .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
+ .addClass(NullConverterBean.class)
+ .addAsServiceProvider(Converter.class, CustomTypeConverter.class)
+ .addAsResource(new StringAsset("my.prop=1234\n"), "application.properties"))
+ .setExpectedException(DeploymentException.class);
+
+ @Test
+ void nullProperty() {
+
+ }
+
+ @ApplicationScoped
+ static class NullConverterBean {
+ @Inject
+ @ConfigProperty(name = "my.prop", defaultValue = "1234")
+ CustomType customType;
+ }
+
+ static class CustomType {
+
+ }
+
+ public static class CustomTypeConverter implements Converter {
+ @Override
+ public CustomTypeConverter convert(final String value)
+ throws IllegalArgumentException, NullPointerException {
+ return null;
+ }
+ }
+}
diff --git a/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/ConfigBeanCreator.java b/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/ConfigBeanCreator.java
index 3f652d1dade3fd..88092c81b6bb84 100644
--- a/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/ConfigBeanCreator.java
+++ b/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/ConfigBeanCreator.java
@@ -1,22 +1,18 @@
package io.quarkus.arc.runtime;
-import java.lang.annotation.Annotation;
import java.util.Map;
-import java.util.Optional;
import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.DeploymentException;
import javax.enterprise.inject.spi.InjectionPoint;
-import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.ConfigProvider;
-import org.eclipse.microprofile.config.inject.ConfigProperty;
import io.quarkus.arc.BeanCreator;
import io.quarkus.arc.impl.InjectionPointProvider;
-import io.smallrye.config.SmallRyeConfig;
+import io.smallrye.config.inject.ConfigProducerUtil;
public class ConfigBeanCreator implements BeanCreator