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> 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 event = Arc.container().beanManager().getEvent(); + // TODO - quarkus.security.events.enabled was marked as runtime, but providers are initialized during static init this.eventHelper = new SecurityEventHelper<>(event.select(AuthorizationSuccessEvent.class), event.select(AuthorizationFailureEvent.class), AUTHORIZATION_SUCCESS, AUTHORIZATION_FAILURE, Arc.container().beanManager(), diff --git a/extensions/security/runtime/src/main/java/io/quarkus/security/runtime/SecurityConfig.java b/extensions/security/runtime/src/main/java/io/quarkus/security/runtime/SecurityConfig.java index 6a1a3aafd24be..f56829bb2eaca 100644 --- a/extensions/security/runtime/src/main/java/io/quarkus/security/runtime/SecurityConfig.java +++ b/extensions/security/runtime/src/main/java/io/quarkus/security/runtime/SecurityConfig.java @@ -9,7 +9,7 @@ * Quarkus Security configuration. */ @ConfigMapping(prefix = "quarkus.security") -@ConfigRoot(phase = ConfigPhase.RUN_TIME) +@ConfigRoot(phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED) public interface SecurityConfig { /** diff --git a/integration-tests/jpa-postgresql-withxml/src/test/resources/image-metrics/23.0/image-metrics.properties b/integration-tests/jpa-postgresql-withxml/src/test/resources/image-metrics/23.0/image-metrics.properties index fd63c5b2782ea..5968543202550 100644 --- a/integration-tests/jpa-postgresql-withxml/src/test/resources/image-metrics/23.0/image-metrics.properties +++ b/integration-tests/jpa-postgresql-withxml/src/test/resources/image-metrics/23.0/image-metrics.properties @@ -9,7 +9,7 @@ analysis_results.fields.reachable=30176 analysis_results.fields.reachable.tolerance=3 analysis_results.types.reflection=6585 analysis_results.types.reflection.tolerance=3 -analysis_results.methods.reflection=4786 +analysis_results.methods.reflection=4556 analysis_results.methods.reflection.tolerance=3 analysis_results.fields.reflection=147 analysis_results.fields.reflection.tolerance=3 diff --git a/integration-tests/jpa-postgresql-withxml/src/test/resources/image-metrics/23.1/image-metrics.properties b/integration-tests/jpa-postgresql-withxml/src/test/resources/image-metrics/23.1/image-metrics.properties index 72ad4d86c1d53..ecf426c1c4d39 100644 --- a/integration-tests/jpa-postgresql-withxml/src/test/resources/image-metrics/23.1/image-metrics.properties +++ b/integration-tests/jpa-postgresql-withxml/src/test/resources/image-metrics/23.1/image-metrics.properties @@ -9,7 +9,7 @@ analysis_results.fields.reachable=30098 analysis_results.fields.reachable.tolerance=3 analysis_results.types.reflection=6705 analysis_results.types.reflection.tolerance=3 -analysis_results.methods.reflection=4893 +analysis_results.methods.reflection=4551 analysis_results.methods.reflection.tolerance=3 analysis_results.fields.reflection=170 analysis_results.fields.reflection.tolerance=3 diff --git a/integration-tests/jpa-postgresql/src/test/resources/image-metrics/23.0/image-metrics.properties b/integration-tests/jpa-postgresql/src/test/resources/image-metrics/23.0/image-metrics.properties index 0ee1ad780c651..440f53540d8a9 100644 --- a/integration-tests/jpa-postgresql/src/test/resources/image-metrics/23.0/image-metrics.properties +++ b/integration-tests/jpa-postgresql/src/test/resources/image-metrics/23.0/image-metrics.properties @@ -9,7 +9,7 @@ analysis_results.fields.reachable=27443 analysis_results.fields.reachable.tolerance=3 analysis_results.types.reflection=6128 analysis_results.types.reflection.tolerance=3 -analysis_results.methods.reflection=4608 +analysis_results.methods.reflection=4374 analysis_results.methods.reflection.tolerance=3 analysis_results.fields.reflection=176 analysis_results.fields.reflection.tolerance=3 diff --git a/integration-tests/jpa-postgresql/src/test/resources/image-metrics/23.1/image-metrics.properties b/integration-tests/jpa-postgresql/src/test/resources/image-metrics/23.1/image-metrics.properties index 553ae245754f0..4ab0d647c3004 100644 --- a/integration-tests/jpa-postgresql/src/test/resources/image-metrics/23.1/image-metrics.properties +++ b/integration-tests/jpa-postgresql/src/test/resources/image-metrics/23.1/image-metrics.properties @@ -9,7 +9,7 @@ analysis_results.fields.reachable=27389 analysis_results.fields.reachable.tolerance=3 analysis_results.types.reflection=6232 analysis_results.types.reflection.tolerance=3 -analysis_results.methods.reflection=4708 +analysis_results.methods.reflection=4367 analysis_results.methods.reflection.tolerance=3 analysis_results.fields.reflection=201 analysis_results.fields.reflection.tolerance=3 diff --git a/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/Alias.java b/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/Alias.java index 93871c1606b78..83674ecd9918d 100644 --- a/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/Alias.java +++ b/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/Alias.java @@ -4,6 +4,9 @@ import com.fasterxml.jackson.annotation.JsonProperty; +import io.quarkus.runtime.annotations.RegisterForReflection; + +@RegisterForReflection public interface Alias extends Named { @JsonProperty Optional alias(); diff --git a/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/Cloud.java b/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/Cloud.java index c9436f55f9c09..74fd78e03b5e5 100644 --- a/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/Cloud.java +++ b/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/Cloud.java @@ -1,13 +1,136 @@ package io.quarkus.it.smallrye.config; +import java.time.Duration; +import java.time.Period; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.OptionalInt; + +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Size; + import io.quarkus.arc.Unremovable; +import io.quarkus.runtime.configuration.DurationConverter; import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithConverter; +import io.smallrye.config.WithDefault; +import io.smallrye.config.WithName; import io.smallrye.config.WithParentName; @Unremovable @ConfigMapping(prefix = "cloud") @Prod public interface Cloud { + String host(); + + @Min(8000) + int port(); + + @WithConverter(DurationConverter.class) + Duration timeout(); + + @WithName("io-threads") + int threads(); + @WithParentName - Server server(); + Map form(); + + Optional ssl(); + + Optional proxy(); + + Optional cors(); + + Log log(); + + Info info(); + + interface Form { + String loginPage(); + + String errorPage(); + + String landingPage(); + + Optional cookie(); + + @WithDefault("1") + List positions(); + } + + interface Ssl { + int port(); + + String certificate(); + + @WithDefault("TLSv1.3,TLSv1.2") + List protocols(); + } + + interface Proxy { + boolean enable(); + + @Max(10) + int timeout(); + } + + interface Log { + @WithDefault("false") + boolean enabled(); + + @WithDefault(".log") + String suffix(); + + @WithDefault("true") + boolean rotate(); + + @WithDefault("COMMON") + Pattern pattern(); + + Period period(); + + @Max(15) + int days(); + + enum Pattern { + COMMON, + SHORT, + COMBINED, + LONG; + } + } + + interface Cors { + List origins(); + + List<@Size(min = 2) String> methods(); + + interface Origin { + @Size(min = 5) + String host(); + + @Min(8000) + int port(); + } + } + + interface Info { + Optional<@Size(max = 3) String> name(); + + @Max(3) + OptionalInt code(); + + Optional> alias(); + + Map> admins(); + + Map> firewall(); + + interface Admin { + @Size(max = 4) + String username(); + } + } } diff --git a/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/Named.java b/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/Named.java index edc3c43fcf0cc..4afc7e8adb472 100644 --- a/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/Named.java +++ b/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/Named.java @@ -4,6 +4,9 @@ import com.fasterxml.jackson.annotation.JsonProperty; +import io.quarkus.runtime.annotations.RegisterForReflection; + +@RegisterForReflection public interface Named { @JsonProperty Optional name(); diff --git a/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/Prod.java b/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/Prod.java index 8926ce36b4107..0387cabd46b58 100644 --- a/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/Prod.java +++ b/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/Prod.java @@ -23,7 +23,7 @@ class Validator implements ConstraintValidator { @Override public boolean isValid(final Cloud value, final ConstraintValidatorContext context) { - return value.server().equals("prod"); + return value.host().equals("prod"); } } } diff --git a/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/Server.java b/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/Server.java index b5a51a4289c11..4fd4ab189f423 100644 --- a/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/Server.java +++ b/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/Server.java @@ -8,10 +8,6 @@ import java.util.Optional; import java.util.OptionalInt; -import jakarta.validation.constraints.Max; -import jakarta.validation.constraints.Min; -import jakarta.validation.constraints.Size; - import org.eclipse.microprofile.config.spi.Converter; import com.fasterxml.jackson.annotation.JsonProperty; @@ -25,12 +21,12 @@ import io.smallrye.config.WithParentName; @ConfigMapping(prefix = "http.server") +@RegisterForReflection public interface Server extends Alias { @JsonProperty String host(); @JsonProperty - @Min(8000) int port(); @JsonProperty @@ -63,6 +59,7 @@ public interface Server extends Alias { @JsonProperty Info info(); + @RegisterForReflection interface Form { @JsonProperty String loginPage(); @@ -81,15 +78,16 @@ interface Form { List positions(); } + @RegisterForReflection interface Proxy { @JsonProperty boolean enable(); @JsonProperty - @Max(10) int timeout(); } + @RegisterForReflection interface Log { @JsonProperty @WithDefault("false") @@ -111,7 +109,6 @@ interface Log { Period period(); @JsonProperty - @Max(15) int days(); @RegisterForReflection @@ -123,44 +120,44 @@ enum Pattern { } } + @RegisterForReflection interface Cors { @JsonProperty List origins(); @JsonProperty - List<@Size(min = 2) String> methods(); + List methods(); + @RegisterForReflection interface Origin { @JsonProperty - @Size(min = 5) String host(); @JsonProperty - @Min(8000) int port(); } } + @RegisterForReflection interface Info { @JsonProperty - Optional<@Size(max = 3) String> name(); + Optional name(); @JsonProperty - @Max(3) OptionalInt code(); @JsonProperty - Optional> alias(); + Optional> alias(); @JsonProperty Map> admins(); @JsonProperty - Map> firewall(); + Map> firewall(); + @RegisterForReflection interface Admin { @JsonProperty - @Size(max = 4) String username(); } } diff --git a/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/ServerResource.java b/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/ServerResource.java index 02104ce29d8e8..69205f27a8553 100644 --- a/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/ServerResource.java +++ b/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/ServerResource.java @@ -1,6 +1,5 @@ package io.quarkus.it.smallrye.config; -import java.lang.reflect.Method; import java.util.List; import jakarta.enterprise.inject.Instance; @@ -40,13 +39,6 @@ public Response getServer() { return Response.ok(server).build(); } - @GET - @Path("/host") - public Response getServerHost() throws Exception { - Method method = server.getClass().getDeclaredMethod("host"); - return Response.ok(method.invoke(server)).build(); - } - @GET @Path("/properties") public Response getServerProperties() { diff --git a/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/Ssl.java b/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/Ssl.java index 684e6af788067..57360cf9bccd0 100644 --- a/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/Ssl.java +++ b/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/Ssl.java @@ -4,9 +4,10 @@ import com.fasterxml.jackson.annotation.JsonProperty; +import io.quarkus.runtime.annotations.RegisterForReflection; import io.smallrye.config.WithDefault; -// TODO - Add hierarchy here but requires https://github.com/smallrye/smallrye-config/pull/590 +@RegisterForReflection public interface Ssl { @JsonProperty int port(); diff --git a/integration-tests/smallrye-config/src/main/resources/application.yaml b/integration-tests/smallrye-config/src/main/resources/application.yaml index 1387ba1876750..7da81f0bee2be 100644 --- a/integration-tests/smallrye-config/src/main/resources/application.yaml +++ b/integration-tests/smallrye-config/src/main/resources/application.yaml @@ -36,7 +36,7 @@ http: cloud: host: localhost - port: 8080 + port: 5000 timeout: 60s io-threads: 200 diff --git a/integration-tests/smallrye-config/src/test/java/io/quarkus/it/smallrye/config/AppConfigTest.java b/integration-tests/smallrye-config/src/test/java/io/quarkus/it/smallrye/config/AppConfigTest.java index 4bf31bd20eff0..2f6a838574ce1 100644 --- a/integration-tests/smallrye-config/src/test/java/io/quarkus/it/smallrye/config/AppConfigTest.java +++ b/integration-tests/smallrye-config/src/test/java/io/quarkus/it/smallrye/config/AppConfigTest.java @@ -22,6 +22,6 @@ void getToString() { containsString("name=app"), containsString("count=10"), containsString("alias=alias"), - endsWith("}}")); + endsWith("}")); } } diff --git a/integration-tests/smallrye-config/src/test/java/io/quarkus/it/smallrye/config/ServerResourceTest.java b/integration-tests/smallrye-config/src/test/java/io/quarkus/it/smallrye/config/ServerResourceTest.java index fc087b8579ca8..400df4f21f128 100644 --- a/integration-tests/smallrye-config/src/test/java/io/quarkus/it/smallrye/config/ServerResourceTest.java +++ b/integration-tests/smallrye-config/src/test/java/io/quarkus/it/smallrye/config/ServerResourceTest.java @@ -47,15 +47,6 @@ void mapping() { .body("log.period", equalTo("P1D")); } - @Test - void serverHost() { - given() - .get("/server/host") - .then() - .statusCode(OK.getStatusCode()) - .body(equalTo("localhost")); - } - @Test void properties() { given() @@ -93,7 +84,8 @@ void invalid() { .get("/server/validator/{prefix}", "cloud") .then() .statusCode(OK.getStatusCode()) - .body("errors", hasSize(9)) + .body("errors", hasSize(10)) + .body("errors", hasItem("cloud.port must be greater than or equal to 8000")) .body("errors", hasItem("cloud.log.days must be less than or equal to 15")) .body("errors", hasItem("cloud.cors.origins[1].port must be greater than or equal to 8000")) .body("errors", hasItem("cloud.info.name size must be between 0 and 3"))