diff --git a/bom/application/pom.xml b/bom/application/pom.xml
index 8798dddc39533..3d5fd38ce4b82 100644
--- a/bom/application/pom.xml
+++ b/bom/application/pom.xml
@@ -51,7 +51,7 @@
2.0
3.1.1
2.3.0
- 3.7.1
+ 3.8.1
4.1.0
4.0.0
3.10.0
diff --git a/core/deployment/pom.xml b/core/deployment/pom.xml
index 852e752a75c70..059176771f34b 100644
--- a/core/deployment/pom.xml
+++ b/core/deployment/pom.xml
@@ -50,6 +50,10 @@
io.quarkus
quarkus-development-mode-spi
+
+ io.quarkus
+ quarkus-hibernate-validator-spi
+
io.quarkus
quarkus-class-change-agent
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/builditem/ConfigClassBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/builditem/ConfigClassBuildItem.java
index d2a6056706789..6369ddf95d9d5 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/builditem/ConfigClassBuildItem.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/builditem/ConfigClassBuildItem.java
@@ -10,6 +10,10 @@
public final class ConfigClassBuildItem extends MultiBuildItem {
private final Class> configClass;
+ /**
+ * All the config interfaces registered for this config mapping (including the nested ones)
+ */
+ private final Set> configComponentInterfaces;
private final Set types;
private final Set generatedClasses;
private final String prefix;
@@ -19,12 +23,14 @@ public final class ConfigClassBuildItem extends MultiBuildItem {
public ConfigClassBuildItem(
final Class> configClass,
+ final Set> configComponentInterfaces,
final Set types,
final Set generatedClasses,
final String prefix,
final Kind kind) {
this.configClass = configClass;
+ this.configComponentInterfaces = configComponentInterfaces;
this.types = types;
this.generatedClasses = generatedClasses;
this.prefix = prefix;
@@ -36,6 +42,10 @@ public Class> getConfigClass() {
return configClass;
}
+ public Set> getConfigComponentInterfaces() {
+ return configComponentInterfaces;
+ }
+
public Set getTypes() {
return types;
}
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 62ef5f74e3043..f914804324801 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
@@ -524,12 +524,6 @@ ReadResult run() {
buildTimeRunTimeValues.putAll(getDefaults(config, buildTimeRunTimePatternMap));
runTimeDefaultValues.putAll(getDefaults(runtimeConfig, runTimePatternMap));
- // Register defaults for Mappings
- // Runtime defaults are added in ConfigGenerationBuildStep.generateBuilders to include user mappings
- for (ConfigClassWithPrefix buildTimeRunTimeMapping : buildTimeRunTimeMappings) {
- buildTimeRunTimeValues.putAll(ConfigMappings.getDefaults(buildTimeRunTimeMapping));
- }
-
Set registeredRoots = allRoots.stream().map(RootDefinition::getName).collect(toSet());
registeredRoots.add("quarkus");
Set allProperties = getAllProperties(registeredRoots);
@@ -1118,7 +1112,7 @@ public Set getPropertyNames() {
}
});
- String[] profiles = config.getProfiles().toArray(String[]::new);
+ List profiles = config.getProfiles();
for (String property : builder.build().getPropertyNames()) {
properties.add(ProfileConfigSourceInterceptor.activeName(property, profiles));
}
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 3617c0a0a1b31..293ef9e3b3dbc 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
@@ -25,7 +25,9 @@
import io.quarkus.deployment.builditem.ConfigClassBuildItem.Kind;
import io.quarkus.deployment.builditem.GeneratedClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
+import io.quarkus.deployment.builditem.nativeimage.ReflectiveMethodBuildItem;
import io.quarkus.deployment.util.ReflectUtil;
+import io.quarkus.hibernate.validator.spi.AdditionalConstrainedClassBuildItem;
import io.smallrye.config.ConfigMapping;
import io.smallrye.config.ConfigMappingInterface;
import io.smallrye.config.ConfigMappingInterface.LeafProperty;
@@ -46,7 +48,9 @@ public static void processConfigClasses(
CombinedIndexBuildItem combinedIndex,
BuildProducer generatedClasses,
BuildProducer reflectiveClasses,
+ BuildProducer reflectiveMethods,
BuildProducer configClasses,
+ BuildProducer additionalConstrainedClasses,
DotName configAnnotation) {
for (AnnotationInstance instance : combinedIndex.getIndex().getAnnotations(configAnnotation)) {
@@ -61,7 +65,7 @@ public static void processConfigClasses(
String prefix = Optional.ofNullable(annotationPrefix).map(AnnotationValue::asString).orElse("");
Kind configClassKind = getConfigClassType(instance);
processConfigClass(configClassWithPrefix(configClass, prefix), configClassKind, true, combinedIndex,
- generatedClasses, reflectiveClasses, configClasses);
+ generatedClasses, reflectiveClasses, reflectiveMethods, configClasses, additionalConstrainedClasses);
}
}
@@ -69,8 +73,11 @@ public static void processConfigMapping(
CombinedIndexBuildItem combinedIndex,
BuildProducer generatedClasses,
BuildProducer reflectiveClasses,
- BuildProducer configClasses) {
- processConfigClasses(combinedIndex, generatedClasses, reflectiveClasses, configClasses, CONFIG_MAPPING_NAME);
+ BuildProducer reflectiveMethods,
+ BuildProducer configClasses,
+ BuildProducer additionalConstrainedClasses) {
+ processConfigClasses(combinedIndex, generatedClasses, reflectiveClasses, reflectiveMethods, configClasses,
+ additionalConstrainedClasses, CONFIG_MAPPING_NAME);
}
public static void processExtensionConfigMapping(
@@ -78,10 +85,12 @@ public static void processExtensionConfigMapping(
CombinedIndexBuildItem combinedIndex,
BuildProducer generatedClasses,
BuildProducer reflectiveClasses,
- BuildProducer configClasses) {
+ BuildProducer reflectiveMethods,
+ BuildProducer configClasses,
+ BuildProducer additionalConstrainedClasses) {
processConfigClass(configClass, Kind.MAPPING, false, combinedIndex, generatedClasses, reflectiveClasses,
- configClasses);
+ reflectiveMethods, configClasses, additionalConstrainedClasses);
}
private static void processConfigClass(
@@ -91,30 +100,37 @@ private static void processConfigClass(
CombinedIndexBuildItem combinedIndex,
BuildProducer generatedClasses,
BuildProducer reflectiveClasses,
- BuildProducer configClasses) {
+ BuildProducer reflectiveMethods,
+ BuildProducer configClasses,
+ BuildProducer additionalConstrainedClasses) {
Class> configClass = configClassWithPrefix.getKlass();
String prefix = configClassWithPrefix.getPrefix();
List configMappingsMetadata = ConfigMappingLoader.getConfigMappingsMetadata(configClass);
Set generatedClassesNames = new HashSet<>();
+ // all the config interfaces including nested ones
+ Set> configComponentInterfaces = new HashSet<>();
configMappingsMetadata.forEach(mappingMetadata -> {
generatedClassesNames.add(mappingMetadata.getClassName());
// This is the generated implementation of the mapping by SmallRye Config.
+ byte[] classBytes = mappingMetadata.getClassBytes();
generatedClasses.produce(new GeneratedClassBuildItem(isApplicationClass, mappingMetadata.getClassName(),
- mappingMetadata.getClassBytes()));
- // Register the interface and implementation methods for reflection. This is required for Bean Validation.
- reflectiveClasses.produce(ReflectiveClassBuildItem.builder(mappingMetadata.getInterfaceType()).methods().build());
- reflectiveClasses.produce(ReflectiveClassBuildItem.builder(mappingMetadata.getClassName()).methods().build());
- // Register also the interface hierarchy
- for (Class> parent : getHierarchy(mappingMetadata.getInterfaceType())) {
- reflectiveClasses.produce(ReflectiveClassBuildItem.builder(parent).methods().build());
- }
+ classBytes));
+ additionalConstrainedClasses.produce(AdditionalConstrainedClassBuildItem.of(mappingMetadata.getClassName(),
+ classBytes));
+ reflectiveClasses.produce(ReflectiveClassBuildItem.builder(mappingMetadata.getClassName()).constructors().build());
+ reflectiveMethods
+ .produce(new ReflectiveMethodBuildItem(mappingMetadata.getClassName(), "getDefaults", new String[0]));
+ reflectiveMethods.produce(new ReflectiveMethodBuildItem(mappingMetadata.getClassName(), "getNames", new String[0]));
+
+ configComponentInterfaces.add(mappingMetadata.getInterfaceType());
processProperties(mappingMetadata.getInterfaceType(), reflectiveClasses);
});
- configClasses.produce(new ConfigClassBuildItem(configClass, collectTypes(combinedIndex, configClass),
+ configClasses.produce(new ConfigClassBuildItem(configClass, configComponentInterfaces,
+ collectTypes(combinedIndex, configClass),
generatedClassesNames, prefix, configClassKind));
}
@@ -125,7 +141,6 @@ private static void processProperties(
ConfigMappingInterface mapping = ConfigMappingLoader.getConfigMapping(configClass);
for (Property property : mapping.getProperties()) {
Class> returnType = property.getMethod().getReturnType();
- reflectiveClasses.produce(ReflectiveClassBuildItem.builder(returnType).methods().build());
if (property.hasConvertWith()) {
Class extends Converter>> convertWith;
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 791010b5438c3..657e2a98d40e0 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
@@ -1197,24 +1197,24 @@ private FieldDescriptor getOrCreateConverterInstance(Field field, ConverterType
Object.class);
private void generateUnknownFilter() {
- Set mappedProperties = new HashSet<>();
+ Set names = new HashSet<>();
for (ConfigClassWithPrefix buildTimeMapping : buildTimeConfigResult.getBuildTimeMappings()) {
- mappedProperties.addAll(ConfigMappings.getKeys(buildTimeMapping));
+ names.addAll(ConfigMappings.getProperties(buildTimeMapping).keySet());
}
for (ConfigClassWithPrefix staticConfigMapping : buildTimeConfigResult.getBuildTimeRunTimeMappings()) {
- mappedProperties.addAll(ConfigMappings.getKeys(staticConfigMapping));
+ names.addAll(ConfigMappings.getProperties(staticConfigMapping).keySet());
}
for (ConfigClassWithPrefix runtimeConfigMapping : buildTimeConfigResult.getRunTimeMappings()) {
- mappedProperties.addAll(ConfigMappings.getKeys(runtimeConfigMapping));
+ names.addAll(ConfigMappings.getProperties(runtimeConfigMapping).keySet());
}
// Add a method that generates a KeyMap that can check if a property is mapped by a @ConfigMapping
MethodCreator mc = cc.getMethodCreator(C_MAPPED_PROPERTIES);
mc.setModifiers(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC);
ResultHandle keyMap = mc.newInstance(KM_NEW);
- for (String mappedProperty : mappedProperties) {
- ResultHandle mappedPropertyKeyMap = mc.invokeVirtualMethod(KM_FIND_OR_ADD, keyMap, mc.load(mappedProperty));
- mc.invokeVirtualMethod(KM_PUT_ROOT_VALUE, mappedPropertyKeyMap, mc.load(true));
+ for (String name : names) {
+ mc.invokeVirtualMethod(KM_PUT_ROOT_VALUE, mc.invokeVirtualMethod(KM_FIND_OR_ADD, keyMap, mc.load(name)),
+ mc.load(true));
}
mc.returnValue(keyMap);
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 93d994f58c834..3e631cca49a24 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
@@ -123,8 +123,7 @@ public void accept(Container node) {
private void processMappings(List mappings, List descriptionBuildItems,
Properties javaDocProperties, ConfigPhase configPhase) {
for (ConfigClassWithPrefix mapping : mappings) {
- Map properties = ConfigMappings.getProperties(mapping).get(mapping.getKlass())
- .get(mapping.getPrefix());
+ Map properties = ConfigMappings.getProperties(mapping);
for (Map.Entry entry : properties.entrySet()) {
String propertyName = entry.getKey();
Property property = entry.getValue();
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 a84ccdd1a0fda..104905ca62a05 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
@@ -59,6 +59,7 @@
import io.quarkus.deployment.builditem.StaticInitConfigBuilderBuildItem;
import io.quarkus.deployment.builditem.SuppressNonRuntimeConfigChangedWarningBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
+import io.quarkus.deployment.builditem.nativeimage.ReflectiveMethodBuildItem;
import io.quarkus.deployment.configuration.BuildTimeConfigurationReader;
import io.quarkus.deployment.configuration.RunTimeConfigurationGenerator;
import io.quarkus.deployment.configuration.tracker.ConfigTrackingConfig;
@@ -73,6 +74,7 @@
import io.quarkus.gizmo.MethodCreator;
import io.quarkus.gizmo.MethodDescriptor;
import io.quarkus.gizmo.ResultHandle;
+import io.quarkus.hibernate.validator.spi.AdditionalConstrainedClassBuildItem;
import io.quarkus.paths.PathCollection;
import io.quarkus.runtime.LaunchMode;
import io.quarkus.runtime.annotations.StaticInitSafe;
@@ -86,7 +88,6 @@
import io.quarkus.runtime.configuration.RuntimeOverrideConfigSource;
import io.quarkus.runtime.configuration.RuntimeOverrideConfigSourceBuilder;
import io.quarkus.runtime.configuration.StaticInitConfigBuilder;
-import io.smallrye.config.ConfigMappings;
import io.smallrye.config.ConfigMappings.ConfigClassWithPrefix;
import io.smallrye.config.ConfigSourceFactory;
import io.smallrye.config.ConfigSourceInterceptor;
@@ -176,19 +177,23 @@ void generateMappings(
CombinedIndexBuildItem combinedIndex,
BuildProducer generatedClasses,
BuildProducer reflectiveClasses,
- BuildProducer configClasses) {
+ BuildProducer reflectiveMethods,
+ BuildProducer configClasses,
+ BuildProducer additionalConstrainedClasses) {
- processConfigMapping(combinedIndex, generatedClasses, reflectiveClasses, configClasses);
+ processConfigMapping(combinedIndex, generatedClasses, reflectiveClasses, reflectiveMethods, configClasses,
+ additionalConstrainedClasses);
List buildTimeRunTimeMappings = configItem.getReadResult().getBuildTimeRunTimeMappings();
for (ConfigClassWithPrefix buildTimeRunTimeMapping : buildTimeRunTimeMappings) {
processExtensionConfigMapping(buildTimeRunTimeMapping, combinedIndex, generatedClasses, reflectiveClasses,
- configClasses);
+ reflectiveMethods, configClasses, additionalConstrainedClasses);
}
List runTimeMappings = configItem.getReadResult().getRunTimeMappings();
for (ConfigClassWithPrefix runTimeMapping : runTimeMappings) {
- processExtensionConfigMapping(runTimeMapping, combinedIndex, generatedClasses, reflectiveClasses, configClasses);
+ processExtensionConfigMapping(runTimeMapping, combinedIndex, generatedClasses, reflectiveClasses, reflectiveMethods,
+ configClasses, additionalConstrainedClasses);
}
}
@@ -203,14 +208,6 @@ void generateBuilders(
BuildProducer reflectiveClass) throws Exception {
Map defaultValues = new HashMap<>();
- // Default values from extensions @ConfigMapping
- for (ConfigClassWithPrefix runTimeMapping : configItem.getReadResult().getRunTimeMappings()) {
- defaultValues.putAll(ConfigMappings.getDefaults(runTimeMapping));
- }
- // Default values from user @ConfigMapping
- for (ConfigMappingBuildItem configMapping : configMappings) {
- defaultValues.putAll(ConfigMappings.getDefaults(configMapping.toConfigClassWithPrefix()));
- }
// Default values from @ConfigRoot
defaultValues.putAll(configItem.getReadResult().getRunTimeDefaultValues());
// Default values from build item RunTimeConfigurationDefaultBuildItem override
@@ -218,7 +215,7 @@ void generateBuilders(
defaultValues.put(e.getKey(), e.getValue());
}
// Recorded values from build time from any other source (higher ordinal then defaults, so override)
- String[] profiles = ConfigProvider.getConfig().unwrap(SmallRyeConfig.class).getProfiles().toArray(String[]::new);
+ List profiles = ConfigProvider.getConfig().unwrap(SmallRyeConfig.class).getProfiles();
for (Map.Entry entry : configItem.getReadResult().getRunTimeValues().entrySet()) {
// Runtime values may contain active profiled names that override sames names in defaults
// We need to keep the original name definition in case a different profile is used to run the app
@@ -244,8 +241,6 @@ void generateBuilders(
staticMappings.addAll(configItem.getReadResult().getBuildTimeRunTimeMappings());
Set staticCustomizers = new HashSet<>(staticSafeServices(configCustomizers));
staticCustomizers.add(StaticInitConfigBuilder.class.getName());
- String staticMappingsInfoClassName = "io.quarkus.runtime.generated.StaticInitMappingsInfo";
- generateMappingsInfo(generatedClass, reflectiveClass, staticMappingsInfoClassName, staticMappings);
generateConfigBuilder(generatedClass, reflectiveClass, CONFIG_STATIC_NAME,
defaultValues,
@@ -257,7 +252,6 @@ void generateBuilders(
staticSafeServices(configSourceFactories),
secretKeyHandlers,
staticSafeServices(secretKeyHandlerFactories),
- staticMappingsInfoClassName,
staticMappings,
staticCustomizers,
staticInitConfigBuilders.stream().map(StaticInitConfigBuilderBuildItem::getBuilderClassName).collect(toSet()));
@@ -270,8 +264,6 @@ void generateBuilders(
runTimeMappings.addAll(configItem.getReadResult().getRunTimeMappings());
Set runtimeCustomizers = new HashSet<>(configCustomizers);
runtimeCustomizers.add(RuntimeConfigBuilder.class.getName());
- String runtimeMappingsInfoClassName = "io.quarkus.runtime.generated.RunTimeMappingsInfo";
- generateMappingsInfo(generatedClass, reflectiveClass, runtimeMappingsInfoClassName, runTimeMappings);
generateConfigBuilder(generatedClass, reflectiveClass, CONFIG_RUNTIME_NAME,
defaultValues,
@@ -283,7 +275,6 @@ void generateBuilders(
configSourceFactories,
secretKeyHandlers,
secretKeyHandlerFactories,
- runtimeMappingsInfoClassName,
runTimeMappings,
runtimeCustomizers,
runTimeConfigBuilders.stream().map(RunTimeConfigBuilderBuildItem::getBuilderClassName).collect(toSet()));
@@ -518,66 +509,6 @@ private static String getPathWithoutExtension(Path path) {
return (dotIndex == -1) ? fileName : fileName.substring(0, dotIndex);
}
- private static final MethodDescriptor MAP_PUT = MethodDescriptor.ofMethod(HashMap.class,
- "put", Object.class, Object.class, Object.class);
- private static final MethodDescriptor SET_ADD = MethodDescriptor.ofMethod(HashSet.class,
- "add", boolean.class, Object.class);
-
- private static void generateMappingsInfo(
- BuildProducer generatedClass,
- BuildProducer reflectiveClass,
- String className,
- Set mappings) {
-
- try (ClassCreator classCreator = ClassCreator.builder()
- .classOutput(new GeneratedClassGizmoAdaptor(generatedClass, true))
- .className(className)
- .setFinal(true)
- .build()) {
-
- for (ConfigMappings.ConfigClassWithPrefix mapping : mappings) {
- generateMappingNames(classCreator, mapping);
- }
-
- MethodCreator keys = classCreator.getMethodCreator("keys", Set.class);
- keys.setModifiers(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC);
- ResultHandle set = keys.checkCast(keys.newInstance(MethodDescriptor.ofConstructor(HashSet.class)), Set.class);
- for (ConfigMappings.ConfigClassWithPrefix mapping : mappings) {
- for (String key : ConfigMappings.getKeys(mapping)) {
- keys.invokeVirtualMethod(SET_ADD, set, keys.load(key));
- }
- }
- keys.returnValue(set);
- }
-
- reflectiveClass.produce(ReflectiveClassBuildItem.builder(className).build());
- }
-
- private static void generateMappingNames(ClassCreator classCreator, ConfigMappings.ConfigClassWithPrefix mapping) {
- MethodCreator method = classCreator.getMethodCreator(
- mapping.getKlass().getName().replaceAll("\\.", "_") + "_" + mapping.getPrefix().hashCode(), Map.class);
- method.setModifiers(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC);
- Map>> properties = ConfigMappings.getNames(mapping);
- ResultHandle map = method.checkCast(
- method.newInstance(MethodDescriptor.ofConstructor(HashMap.class, int.class), method.load(properties.size())),
- Map.class);
- for (Map.Entry>> entry : properties.entrySet()) {
- ResultHandle groups = method.checkCast(method.newInstance(MethodDescriptor.ofConstructor(HashMap.class, int.class),
- method.load(entry.getValue().size())), Map.class);
- for (Map.Entry> group : entry.getValue().entrySet()) {
- ResultHandle names = method
- .checkCast(method.newInstance(MethodDescriptor.ofConstructor(HashSet.class, int.class),
- method.load(group.getValue().size())), Set.class);
- for (String name : group.getValue()) {
- method.invokeVirtualMethod(SET_ADD, names, method.load(name));
- }
- method.invokeVirtualMethod(MAP_PUT, groups, method.load(group.getKey()), names);
- }
- method.invokeVirtualMethod(MAP_PUT, map, method.load(entry.getKey()), groups);
- }
- method.returnValue(map);
- }
-
private static final MethodDescriptor BUILDER_CUSTOMIZER = MethodDescriptor.ofMethod(SmallRyeConfigBuilderCustomizer.class,
"configBuilder",
void.class, SmallRyeConfigBuilder.class);
@@ -635,7 +566,6 @@ private static void generateConfigBuilder(
Set configSourceFactories,
Set secretKeyHandlers,
Set secretKeyHandlerFactories,
- String mappingsInfoClassName,
Set mappings,
Set configCustomizers,
Set configBuilders) {
@@ -700,13 +630,7 @@ private static void generateConfigBuilder(
for (ConfigClassWithPrefix mapping : mappings) {
method.invokeStaticMethod(WITH_MAPPING, configBuilder, method.load(mapping.getKlass().getName()),
method.load(mapping.getPrefix()));
- ResultHandle names = method.invokeStaticMethod(MethodDescriptor.ofMethod(mappingsInfoClassName,
- mapping.getKlass().getName().replaceAll("\\.", "_") + "_" + mapping.getPrefix().hashCode(), Map.class));
- method.invokeVirtualMethod(WITH_NAMES, configBuilder, names);
}
- ResultHandle keys = method
- .invokeStaticMethod(MethodDescriptor.ofMethod(mappingsInfoClassName, "keys", Set.class));
- method.invokeVirtualMethod(WITH_KEYS, configBuilder, keys);
method.returnVoid();
}
diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/RuntimeConfigBuilder.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/RuntimeConfigBuilder.java
index b8cd9691775f8..d20c66f8a36f9 100644
--- a/core/runtime/src/main/java/io/quarkus/runtime/configuration/RuntimeConfigBuilder.java
+++ b/core/runtime/src/main/java/io/quarkus/runtime/configuration/RuntimeConfigBuilder.java
@@ -13,8 +13,6 @@ public class RuntimeConfigBuilder implements SmallRyeConfigBuilderCustomizer {
@Override
public void configBuilder(final SmallRyeConfigBuilder builder) {
new QuarkusConfigBuilderCustomizer().configBuilder(builder);
- builder.withMappingDefaults(false);
-
builder.withDefaultValue("quarkus.uuid", UUID.randomUUID().toString());
builder.forClassLoader(Thread.currentThread().getContextClassLoader())
diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/StaticInitConfigBuilder.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/StaticInitConfigBuilder.java
index b45028fa991d0..d27c3bbb1e2e2 100644
--- a/core/runtime/src/main/java/io/quarkus/runtime/configuration/StaticInitConfigBuilder.java
+++ b/core/runtime/src/main/java/io/quarkus/runtime/configuration/StaticInitConfigBuilder.java
@@ -11,7 +11,6 @@ public class StaticInitConfigBuilder implements SmallRyeConfigBuilderCustomizer
@Override
public void configBuilder(final SmallRyeConfigBuilder builder) {
new QuarkusConfigBuilderCustomizer().configBuilder(builder);
- builder.withMappingDefaults(false);
builder.forClassLoader(Thread.currentThread().getContextClassLoader())
.addDefaultInterceptors()
diff --git a/devtools/cli/src/main/java/io/quarkus/cli/config/SetConfig.java b/devtools/cli/src/main/java/io/quarkus/cli/config/SetConfig.java
index bafb7fe6c38b0..a88915808094a 100644
--- a/devtools/cli/src/main/java/io/quarkus/cli/config/SetConfig.java
+++ b/devtools/cli/src/main/java/io/quarkus/cli/config/SetConfig.java
@@ -8,6 +8,7 @@
import java.util.concurrent.Callable;
import io.smallrye.config.ConfigValue;
+import io.smallrye.config.Converters;
import picocli.CommandLine;
@CommandLine.Command(name = "set")
@@ -46,6 +47,12 @@ public Integer call() throws Exception {
if (encryptionKey.getValue() != null) {
args.add("--key=" + encryptionKey.getValue());
}
+ ConfigValue encryptionDecode = findKey(lines,
+ "smallrye.config.secret-handler.aes-gcm-nopadding.encryption-key-decode");
+ if (encryptionDecode.getValue() == null
+ || !Converters.getImplicitConverter(Boolean.class).convert(encryptionDecode.getValue())) {
+ args.add("--format=plain");
+ }
int execute = new CommandLine(encrypt).execute(args.toArray(new String[] {}));
if (execute < 0) {
diff --git a/devtools/cli/src/test/java/io/quarkus/cli/config/SetConfigTest.java b/devtools/cli/src/test/java/io/quarkus/cli/config/SetConfigTest.java
index 7cbfccc663102..259b0afc8cece 100644
--- a/devtools/cli/src/test/java/io/quarkus/cli/config/SetConfigTest.java
+++ b/devtools/cli/src/test/java/io/quarkus/cli/config/SetConfigTest.java
@@ -81,7 +81,6 @@ void createEncryptedConfiguration() throws Exception {
assertTrue(result.getStdout().contains("Adding foo.bar"));
SmallRyeConfig config = config();
- assertEquals("aes-gcm-nopadding", config.getConfigValue("foo.bar").getExtendedExpressionHandler());
assertEquals("1234", config.getConfigValue("foo.bar").getValue());
String encryption = config.getRawValue("smallrye.config.secret-handler.aes-gcm-nopadding.encryption-key");
@@ -93,13 +92,9 @@ void createEncryptedConfiguration() throws Exception {
config = config();
- assertEquals("aes-gcm-nopadding", config.getConfigValue("foo.bar").getExtendedExpressionHandler());
assertEquals("1234", config.getConfigValue("foo.bar").getValue());
assertTrue(config.isPropertyPresent("foo.baz"));
-
- // TODO - radcortez - Requires update in SmallRye Config
- //assertEquals("aes-gcm-nopadding", config.getConfigValue("foo.baz").getExtendedExpressionHandler());
- //assertEquals("5678", config.getConfigValue("foo.baz").getValue());
+ assertEquals("5678", config.getConfigValue("foo.baz").getValue());
}
@Test
@@ -118,14 +113,12 @@ void updateEncryptedConfiguration() throws Exception {
assertEquals(0, result.getExitCode());
SmallRyeConfig config = config();
- assertEquals("aes-gcm-nopadding", config.getConfigValue("foo.bar").getExtendedExpressionHandler());
assertEquals("1234", config.getConfigValue("foo.bar").getValue());
}
private SmallRyeConfig config() throws Exception {
- final PropertiesConfigSource propertiesConfigSource = new PropertiesConfigSource(
+ PropertiesConfigSource propertiesConfigSource = new PropertiesConfigSource(
tempDir.resolve("src/main/resources/application.properties").toUri().toURL());
- System.out.println(propertiesConfigSource.getProperties());
return new SmallRyeConfigBuilder()
.addDefaultInterceptors()
.addDiscoveredSecretKeysHandlers()
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 8e9dce3d6591d..e553cca9386e5 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
@@ -68,9 +68,11 @@
import io.quarkus.deployment.builditem.ConfigurationBuildItem;
import io.quarkus.deployment.builditem.GeneratedClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
+import io.quarkus.deployment.builditem.nativeimage.ReflectiveMethodBuildItem;
import io.quarkus.deployment.configuration.definition.RootDefinition;
import io.quarkus.deployment.recording.RecorderContext;
import io.quarkus.gizmo.ResultHandle;
+import io.quarkus.hibernate.validator.spi.AdditionalConstrainedClassBuildItem;
import io.quarkus.runtime.annotations.ConfigPhase;
import io.smallrye.config.ConfigMappings.ConfigClassWithPrefix;
import io.smallrye.config.inject.ConfigProducer;
@@ -287,9 +289,12 @@ void generateConfigProperties(
CombinedIndexBuildItem combinedIndex,
BuildProducer generatedClasses,
BuildProducer reflectiveClasses,
- BuildProducer configClasses) {
+ BuildProducer reflectiveMethods,
+ BuildProducer configClasses,
+ BuildProducer additionalConstrainedClasses) {
- processConfigClasses(combinedIndex, generatedClasses, reflectiveClasses, configClasses, MP_CONFIG_PROPERTIES_NAME);
+ processConfigClasses(combinedIndex, generatedClasses, reflectiveClasses, reflectiveMethods, configClasses,
+ additionalConstrainedClasses, MP_CONFIG_PROPERTIES_NAME);
}
@BuildStep
@@ -489,6 +494,7 @@ void registerConfigClasses(
List configMappings,
List configProperties) throws Exception {
+ // TODO - Register ConfigProperties during build time
context.registerNonDefaultConstructor(
ConfigClassWithPrefix.class.getDeclaredConstructor(Class.class, String.class),
configClassWithPrefix -> Stream.of(configClassWithPrefix.getKlass(), configClassWithPrefix.getPrefix())
diff --git a/extensions/hibernate-validator/deployment/src/main/java/io/quarkus/hibernate/validator/deployment/HibernateValidatorProcessor.java b/extensions/hibernate-validator/deployment/src/main/java/io/quarkus/hibernate/validator/deployment/HibernateValidatorProcessor.java
index a2be59f4ba30f..ac67b9da6484f 100644
--- a/extensions/hibernate-validator/deployment/src/main/java/io/quarkus/hibernate/validator/deployment/HibernateValidatorProcessor.java
+++ b/extensions/hibernate-validator/deployment/src/main/java/io/quarkus/hibernate/validator/deployment/HibernateValidatorProcessor.java
@@ -2,6 +2,8 @@
import static io.quarkus.deployment.annotations.ExecutionTime.STATIC_INIT;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
import java.lang.annotation.Repeatable;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
@@ -43,8 +45,10 @@
import org.jboss.jandex.CompositeIndex;
import org.jboss.jandex.DotName;
import org.jboss.jandex.IndexView;
+import org.jboss.jandex.Indexer;
import org.jboss.jandex.MethodInfo;
import org.jboss.jandex.Type;
+import org.jboss.logging.Logger;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -60,6 +64,7 @@
import io.quarkus.arc.processor.BuiltinScope;
import io.quarkus.arc.processor.DotNames;
import io.quarkus.bootstrap.classloading.QuarkusClassLoader;
+import io.quarkus.builder.item.SimpleBuildItem;
import io.quarkus.deployment.Capabilities;
import io.quarkus.deployment.Capability;
import io.quarkus.deployment.Feature;
@@ -103,6 +108,7 @@
import io.quarkus.hibernate.validator.runtime.jaxrs.ResteasyReactiveViolationExceptionMapper;
import io.quarkus.hibernate.validator.runtime.jaxrs.ResteasyViolationExceptionMapper;
import io.quarkus.hibernate.validator.runtime.jaxrs.ViolationReport;
+import io.quarkus.hibernate.validator.spi.AdditionalConstrainedClassBuildItem;
import io.quarkus.hibernate.validator.spi.BeanValidationAnnotationsBuildItem;
import io.quarkus.jaxrs.spi.deployment.AdditionalJaxRsResourceMethodAnnotationsBuildItem;
import io.quarkus.resteasy.common.spi.ResteasyConfigBuildItem;
@@ -111,14 +117,14 @@
import io.quarkus.resteasy.reactive.spi.ExceptionMapperBuildItem;
import io.quarkus.runtime.LocalesBuildTimeConfig;
import io.quarkus.runtime.configuration.ConfigBuilder;
-import io.smallrye.config.ConfigMappingLoader;
-import io.smallrye.config.ConfigMappingMetadata;
import io.smallrye.config.ConfigValidator;
import io.smallrye.config.SmallRyeConfigBuilder;
import io.smallrye.config.validator.BeanValidationConfigValidator;
class HibernateValidatorProcessor {
+ private static final Logger LOG = Logger.getLogger(HibernateValidatorProcessor.class);
+
private static final String META_INF_VALIDATION_XML = "META-INF/validation.xml";
private static final DotName CONSTRAINT_VALIDATOR_FACTORY = DotName
@@ -168,9 +174,19 @@ NativeImageFeatureBuildItem nativeImageFeature() {
void beanValidationAnnotations(
BeanArchiveIndexBuildItem beanArchiveIndexBuildItem,
CombinedIndexBuildItem combinedIndexBuildItem,
+ Optional additionalConstrainedClassesIndexBuildItem,
BuildProducer beanValidationAnnotations) {
- IndexView indexView = CompositeIndex.create(beanArchiveIndexBuildItem.getIndex(), combinedIndexBuildItem.getIndex());
+ IndexView indexView;
+
+ if (additionalConstrainedClassesIndexBuildItem.isPresent()) {
+ // we use both indexes to support both generated beans and jars that contain no CDI beans but only Validation annotations
+ // we also add the additional constrained classes
+ indexView = CompositeIndex.create(beanArchiveIndexBuildItem.getIndex(), combinedIndexBuildItem.getIndex(),
+ additionalConstrainedClassesIndexBuildItem.get().getIndex());
+ } else {
+ indexView = CompositeIndex.create(beanArchiveIndexBuildItem.getIndex(), combinedIndexBuildItem.getIndex());
+ }
Set constraints = new HashSet<>();
Set builtinConstraints = ConstraintHelper.getBuiltinConstraints();
@@ -217,19 +233,24 @@ void configValidator(
Set configMappings = new HashSet<>();
Set configClassesToValidate = new HashSet<>();
+ Map> embeddingMap = new HashMap<>();
for (ConfigClassBuildItem configClass : configClasses) {
for (String generatedConfigClass : configClass.getGeneratedClasses()) {
DotName simple = DotName.createSimple(generatedConfigClass);
configClassesToValidate.add(simple);
}
- for (ConfigMappingMetadata mappingsMetadata : ConfigMappingLoader
- .getConfigMappingsMetadata(configClass.getConfigClass())) {
- configMappings.add(DotName.createSimple(mappingsMetadata.getInterfaceType()));
- }
+ configClass.getConfigComponentInterfaces().stream().map(DotName::createSimple)
+ .forEach(cm -> {
+ configMappings.add(cm);
+ embeddingMap.computeIfAbsent(cm, c -> new HashMap<>())
+ .putIfAbsent(configClass.getName(), configClass);
+ });
}
+ Set constrainedConfigMappings = new HashSet<>();
Set configMappingsConstraints = new HashSet<>();
+
for (DotName consideredAnnotation : beanValidationAnnotations.getAllAnnotations()) {
Collection annotationInstances = combinedIndex.getIndex().getAnnotations(consideredAnnotation);
@@ -246,6 +267,7 @@ void configValidator(
ClassInfo declaringClass = methodInfo.declaringClass();
if (configMappings.contains(declaringClass.name())) {
configMappingsConstraints.add(builtinConstraintCandidate);
+ constrainedConfigMappings.add(declaringClass.name());
}
} else if (annotation.target().kind() == AnnotationTarget.Kind.TYPE) {
AnnotationTarget target = annotation.target().asType().enclosingTarget();
@@ -254,12 +276,14 @@ void configValidator(
ClassInfo declaringClass = methodInfo.declaringClass();
if (configMappings.contains(declaringClass.name())) {
configMappingsConstraints.add(builtinConstraintCandidate);
+ constrainedConfigMappings.add(declaringClass.name());
}
}
} else if (annotation.target().kind() == AnnotationTarget.Kind.CLASS) {
ClassInfo classInfo = annotation.target().asClass();
if (configMappings.contains(classInfo.name())) {
configMappingsConstraints.add(builtinConstraintCandidate);
+ constrainedConfigMappings.add(classInfo.name());
}
}
}
@@ -269,6 +293,26 @@ void configValidator(
return;
}
+ // if in the tree of a ConfigMapping, there is one constraint, we register the whole tree
+ // we might be able to do some more advanced surgery with Jandex evolution but for now
+ // that's the best we can do
+ Set configComponentsInterfacesToRegisterForReflection = new HashSet<>();
+ for (DotName constrainedConfigMapping : constrainedConfigMappings) {
+ if (!embeddingMap.containsKey(constrainedConfigMapping)) {
+ // should never happen but let's be safe
+ continue;
+ }
+
+ embeddingMap.get(constrainedConfigMapping).values().stream()
+ .map(c -> c.getConfigComponentInterfaces())
+ .flatMap(Collection::stream)
+ .map(DotName::createSimple)
+ .forEach(configComponentsInterfacesToRegisterForReflection::add);
+ }
+ reflectiveClass.produce(ReflectiveClassBuildItem.builder(
+ configComponentsInterfacesToRegisterForReflection.stream().map(DotName::toString).toArray(String[]::new))
+ .methods().build());
+
String builderClassName = HibernateBeanValidationConfigValidator.class.getName() + "Builder";
try (ClassCreator classCreator = ClassCreator.builder()
.classOutput(new GeneratedClassGizmoAdaptor(generatedClass, true))
@@ -406,6 +450,7 @@ public void build(
BuildProducer annotationsTransformers,
BeanArchiveIndexBuildItem beanArchiveIndexBuildItem,
CombinedIndexBuildItem combinedIndexBuildItem,
+ Optional additionalConstrainedClassesIndexBuildItem,
BuildProducer feature,
BuildProducer beanContainerListener,
BuildProducer unremovableBeans,
@@ -418,8 +463,16 @@ public void build(
feature.produce(new FeatureBuildItem(Feature.HIBERNATE_VALIDATOR));
- // we use both indexes to support both generated beans and jars that contain no CDI beans but only Validation annotations
- IndexView indexView = CompositeIndex.create(beanArchiveIndexBuildItem.getIndex(), combinedIndexBuildItem.getIndex());
+ IndexView indexView;
+
+ if (additionalConstrainedClassesIndexBuildItem.isPresent()) {
+ // we use both indexes to support both generated beans and jars that contain no CDI beans but only Validation annotations
+ // we also add the additional constrained classes
+ indexView = CompositeIndex.create(beanArchiveIndexBuildItem.getIndex(), combinedIndexBuildItem.getIndex(),
+ additionalConstrainedClassesIndexBuildItem.get().getIndex());
+ } else {
+ indexView = CompositeIndex.create(beanArchiveIndexBuildItem.getIndex(), combinedIndexBuildItem.getIndex());
+ }
Set classNamesToBeValidated = new HashSet<>();
Map> methodsWithInheritedValidation = new HashMap<>();
@@ -537,6 +590,30 @@ public void build(
hibernateValidatorBuildTimeConfig)));
}
+ @BuildStep
+ void indexAdditionalConstrainedClasses(List additionalConstrainedClasses,
+ BuildProducer additionalConstrainedClassesIndex) {
+ if (additionalConstrainedClasses.isEmpty()) {
+ return;
+ }
+
+ // Create an index with additional constrained classes
+ Indexer indexer = new Indexer();
+ for (AdditionalConstrainedClassBuildItem additionalConstrainedClass : additionalConstrainedClasses) {
+ try {
+ if (additionalConstrainedClass.isGenerated()) {
+ indexer.index(new ByteArrayInputStream(additionalConstrainedClass.getBytes()));
+ } else {
+ indexer.indexClass(additionalConstrainedClass.getClazz());
+ }
+ } catch (IOException e) {
+ LOG.warnf(e, "Unable to index constrained class %s", additionalConstrainedClass.getName());
+ }
+ }
+
+ additionalConstrainedClassesIndex.produce(new AdditionalConstrainedClassesIndexBuildItem(indexer.complete()));
+ }
+
@BuildStep
void optionalResourceBundles(BuildProducer resourceBundles) {
String[] potentialHibernateValidatorResourceBundles = {
@@ -728,4 +805,16 @@ private static boolean hasXmlConfiguration() {
return Thread.currentThread().getContextClassLoader().getResource(META_INF_VALIDATION_XML) != null;
}
+ private static final class AdditionalConstrainedClassesIndexBuildItem extends SimpleBuildItem {
+
+ private final IndexView index;
+
+ private AdditionalConstrainedClassesIndexBuildItem(IndexView index) {
+ this.index = index;
+ }
+
+ public IndexView getIndex() {
+ return index;
+ }
+ }
}
diff --git a/extensions/hibernate-validator/spi/pom.xml b/extensions/hibernate-validator/spi/pom.xml
index d9e7a1fb83eb0..a65028dc4e82d 100644
--- a/extensions/hibernate-validator/spi/pom.xml
+++ b/extensions/hibernate-validator/spi/pom.xml
@@ -16,7 +16,11 @@
io.quarkus
- quarkus-core-deployment
+ quarkus-builder
+
+
+ io.smallrye
+ jandex
diff --git a/extensions/hibernate-validator/spi/src/main/java/io/quarkus/hibernate/validator/spi/AdditionalConstrainedClassBuildItem.java b/extensions/hibernate-validator/spi/src/main/java/io/quarkus/hibernate/validator/spi/AdditionalConstrainedClassBuildItem.java
new file mode 100644
index 0000000000000..7bea4b03fb6a1
--- /dev/null
+++ b/extensions/hibernate-validator/spi/src/main/java/io/quarkus/hibernate/validator/spi/AdditionalConstrainedClassBuildItem.java
@@ -0,0 +1,48 @@
+package io.quarkus.hibernate.validator.spi;
+
+import io.quarkus.builder.item.MultiBuildItem;
+
+public final class AdditionalConstrainedClassBuildItem extends MultiBuildItem {
+
+ private static final byte[] EMPTY = new byte[0];
+
+ private final Class> clazz;
+ private final String name;
+ private final byte[] bytes;
+
+ private AdditionalConstrainedClassBuildItem(Class> clazz) {
+ this.clazz = clazz;
+ this.name = clazz.getName();
+ this.bytes = EMPTY;
+ }
+
+ private AdditionalConstrainedClassBuildItem(String name, byte[] bytes) {
+ this.clazz = null;
+ this.name = name;
+ this.bytes = bytes;
+ }
+
+ public static AdditionalConstrainedClassBuildItem of(Class> clazz) {
+ return new AdditionalConstrainedClassBuildItem(clazz);
+ }
+
+ public static AdditionalConstrainedClassBuildItem of(String name, byte[] bytes) {
+ return new AdditionalConstrainedClassBuildItem(name, bytes);
+ }
+
+ public Class> getClazz() {
+ return clazz;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public byte[] getBytes() {
+ return bytes;
+ }
+
+ public boolean isGenerated() {
+ return clazz == null;
+ }
+}
diff --git a/extensions/resteasy-classic/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/EagerSecurityFilter.java b/extensions/resteasy-classic/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/EagerSecurityFilter.java
index 64ea30b5edbfa..fe1ec5ae9c101 100644
--- a/extensions/resteasy-classic/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/EagerSecurityFilter.java
+++ b/extensions/resteasy-classic/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/EagerSecurityFilter.java
@@ -61,6 +61,7 @@ public EagerSecurityFilter() {
var interceptorStorageHandle = Arc.container().instance(EagerSecurityInterceptorStorage.class);
this.interceptorStorage = interceptorStorageHandle.isAvailable() ? interceptorStorageHandle.get() : null;
Event