From 6ad8efd604a787f0c2965d3ececb8644f9a8ae81 Mon Sep 17 00:00:00 2001 From: Roberto Cortez Date: Tue, 22 Jun 2021 15:44:50 +0100 Subject: [PATCH] Register ConfigSources directly with the builder --- ...taticInitConfigSourceFactoryBuildItem.java | 18 ++ ...ticInitConfigSourceProviderBuildItem.java} | 7 +- .../RunTimeConfigurationGenerator.java | 174 +++++++++++++----- .../deployment/steps/ConfigBuildSteps.java | 13 +- .../steps/ConfigGenerationBuildStep.java | 114 +++++++++--- .../ConfigSourceFactoryProvider.java | 7 + .../runtime/configuration/ConfigUtils.java | 4 + .../configuration/RuntimeConfigSource.java | 27 +++ .../RuntimeConfigSourceFactory.java | 25 +++ .../RuntimeConfigSourceProvider.java | 27 +++ .../runtime/configuration/StaticInitSafe.java | 22 +++ .../quarkus/extest/StaticInitSourcesTest.java | 30 +++ .../config/StaticInitNotSafeConfigSource.java | 15 ++ .../config/StaticInitSafeConfigSource.java | 17 ++ .../src/main/asciidoc/writing-extensions.adoc | 2 +- .../deployment/ResteasyCommonProcessor.java | 22 ++- .../common/runtime/graal/ServletMissing.java | 38 ++++ ...icroprofile_config_FilterConfigSource.java | 14 ++ ...croprofile_config_ServletConfigSource.java | 14 ++ ...ile_config_ServletContextConfigSource.java | 15 ++ .../deployment/ResteasyServletProcessor.java | 10 +- .../smallrye-opentracing/runtime/pom.xml | 5 - ...icroprofile_config_FilterConfigSource.java | 33 ---- ...croprofile_config_ServletConfigSource.java | 33 ---- ...ile_config_ServletContextConfigSource.java | 48 ----- .../runtime/graal/UndertowMissing.java | 16 -- .../it/smallrye/config/ConfigResource.java | 11 +- .../config/ConfigurableExceptionMapper.java | 29 +++ .../ConfigurableExceptionMapperResource.java | 16 ++ .../it/smallrye/config/UserConfigSource.java | 22 +++ .../config/UserConfigSourceProvider.java | 17 ++ ...lipse.microprofile.config.spi.ConfigSource | 1 + ...croprofile.config.spi.ConfigSourceProvider | 1 + .../src/main/resources/config.properties | 2 + .../src/main/resources/fallback.properties | 2 + .../main/resources/test-profile.properties | 2 + .../config/ConfigurableExceptionMapperIT.java | 7 + .../ConfigurableExceptionMapperTest.java | 21 +++ .../smallrye/config/SmallRyeConfigTest.java | 17 ++ 39 files changed, 668 insertions(+), 230 deletions(-) create mode 100644 core/deployment/src/main/java/io/quarkus/deployment/builditem/StaticInitConfigSourceFactoryBuildItem.java rename core/deployment/src/main/java/io/quarkus/deployment/builditem/{AdditionalStaticInitConfigSourceProviderBuildItem.java => StaticInitConfigSourceProviderBuildItem.java} (53%) create mode 100644 core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigSourceFactoryProvider.java create mode 100644 core/runtime/src/main/java/io/quarkus/runtime/configuration/RuntimeConfigSource.java create mode 100644 core/runtime/src/main/java/io/quarkus/runtime/configuration/RuntimeConfigSourceFactory.java create mode 100644 core/runtime/src/main/java/io/quarkus/runtime/configuration/RuntimeConfigSourceProvider.java create mode 100644 core/runtime/src/main/java/io/quarkus/runtime/configuration/StaticInitSafe.java create mode 100644 core/test-extension/deployment/src/test/java/io/quarkus/extest/StaticInitSourcesTest.java create mode 100644 core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/config/StaticInitNotSafeConfigSource.java create mode 100644 core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/config/StaticInitSafeConfigSource.java create mode 100644 extensions/resteasy-classic/resteasy-common/runtime/src/main/java/io/quarkus/resteasy/common/runtime/graal/ServletMissing.java create mode 100644 extensions/resteasy-classic/resteasy-common/runtime/src/main/java/io/quarkus/resteasy/common/runtime/graal/Target_org_jboss_resteasy_microprofile_config_FilterConfigSource.java create mode 100644 extensions/resteasy-classic/resteasy-common/runtime/src/main/java/io/quarkus/resteasy/common/runtime/graal/Target_org_jboss_resteasy_microprofile_config_ServletConfigSource.java create mode 100644 extensions/resteasy-classic/resteasy-common/runtime/src/main/java/io/quarkus/resteasy/common/runtime/graal/Target_org_jboss_resteasy_microprofile_config_ServletContextConfigSource.java delete mode 100644 extensions/smallrye-opentracing/runtime/src/main/java/io/quarkus/smallrye/opentracing/runtime/graal/Target_org_jboss_resteasy_microprofile_config_FilterConfigSource.java delete mode 100644 extensions/smallrye-opentracing/runtime/src/main/java/io/quarkus/smallrye/opentracing/runtime/graal/Target_org_jboss_resteasy_microprofile_config_ServletConfigSource.java delete mode 100644 extensions/smallrye-opentracing/runtime/src/main/java/io/quarkus/smallrye/opentracing/runtime/graal/Target_org_jboss_resteasy_microprofile_config_ServletContextConfigSource.java delete mode 100644 extensions/smallrye-opentracing/runtime/src/main/java/io/quarkus/smallrye/opentracing/runtime/graal/UndertowMissing.java create mode 100644 integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/ConfigurableExceptionMapper.java create mode 100644 integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/ConfigurableExceptionMapperResource.java create mode 100644 integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/UserConfigSource.java create mode 100644 integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/UserConfigSourceProvider.java create mode 100644 integration-tests/smallrye-config/src/main/resources/META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource create mode 100644 integration-tests/smallrye-config/src/main/resources/META-INF/services/org.eclipse.microprofile.config.spi.ConfigSourceProvider create mode 100644 integration-tests/smallrye-config/src/test/java/io/quarkus/it/smallrye/config/ConfigurableExceptionMapperIT.java create mode 100644 integration-tests/smallrye-config/src/test/java/io/quarkus/it/smallrye/config/ConfigurableExceptionMapperTest.java diff --git a/core/deployment/src/main/java/io/quarkus/deployment/builditem/StaticInitConfigSourceFactoryBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/builditem/StaticInitConfigSourceFactoryBuildItem.java new file mode 100644 index 0000000000000..1437d1f486afa --- /dev/null +++ b/core/deployment/src/main/java/io/quarkus/deployment/builditem/StaticInitConfigSourceFactoryBuildItem.java @@ -0,0 +1,18 @@ +package io.quarkus.deployment.builditem; + +import io.quarkus.builder.item.MultiBuildItem; + +/** + * Provides a way to register a ConfigSourceFactory in STATIC INIT. + */ +public final class StaticInitConfigSourceFactoryBuildItem extends MultiBuildItem { + private String factoryClassName; + + public StaticInitConfigSourceFactoryBuildItem(final String factoryClassName) { + this.factoryClassName = factoryClassName; + } + + public String getFactoryClassName() { + return factoryClassName; + } +} diff --git a/core/deployment/src/main/java/io/quarkus/deployment/builditem/AdditionalStaticInitConfigSourceProviderBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/builditem/StaticInitConfigSourceProviderBuildItem.java similarity index 53% rename from core/deployment/src/main/java/io/quarkus/deployment/builditem/AdditionalStaticInitConfigSourceProviderBuildItem.java rename to core/deployment/src/main/java/io/quarkus/deployment/builditem/StaticInitConfigSourceProviderBuildItem.java index 1ec5e97b3d997..b56239824e54f 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/builditem/AdditionalStaticInitConfigSourceProviderBuildItem.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/builditem/StaticInitConfigSourceProviderBuildItem.java @@ -2,10 +2,13 @@ import io.quarkus.builder.item.MultiBuildItem; -public final class AdditionalStaticInitConfigSourceProviderBuildItem extends MultiBuildItem { +/** + * Provides a way to register a ConfigSourceProvider in STATIC INIT. + */ +public final class StaticInitConfigSourceProviderBuildItem extends MultiBuildItem { private final String providerClassName; - public AdditionalStaticInitConfigSourceProviderBuildItem(String providerClassName) { + public StaticInitConfigSourceProviderBuildItem(String providerClassName) { this.providerClassName = providerClassName; } 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 83a0e916fba4e..ed359f5e11c2f 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 @@ -60,12 +60,16 @@ import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.configuration.AbstractRawDefaultConfigSource; import io.quarkus.runtime.configuration.ConfigDiagnostic; +import io.quarkus.runtime.configuration.ConfigSourceFactoryProvider; import io.quarkus.runtime.configuration.ConfigUtils; import io.quarkus.runtime.configuration.ConfigurationException; import io.quarkus.runtime.configuration.HyphenateEnumConverter; import io.quarkus.runtime.configuration.NameIterator; import io.quarkus.runtime.configuration.ProfileManager; import io.quarkus.runtime.configuration.QuarkusConfigFactory; +import io.quarkus.runtime.configuration.RuntimeConfigSource; +import io.quarkus.runtime.configuration.RuntimeConfigSourceFactory; +import io.quarkus.runtime.configuration.RuntimeConfigSourceProvider; import io.smallrye.config.Converters; import io.smallrye.config.PropertiesConfigSource; import io.smallrye.config.SmallRyeConfig; @@ -165,6 +169,13 @@ public final class RunTimeConfigurationGenerator { void.class, SmallRyeConfigBuilder.class, ConfigSourceProvider.class); static final MethodDescriptor CU_ADD_SOURCE_PROVIDERS = MethodDescriptor.ofMethod(ConfigUtils.class, "addSourceProviders", void.class, SmallRyeConfigBuilder.class, Collection.class); + static final MethodDescriptor CU_ADD_SOURCE_FACTORY_PROVIDER = MethodDescriptor.ofMethod(ConfigUtils.class, + "addSourceFactoryProvider", + void.class, SmallRyeConfigBuilder.class, ConfigSourceFactoryProvider.class); + + static final MethodDescriptor RCS_NEW = MethodDescriptor.ofConstructor(RuntimeConfigSource.class, String.class); + static final MethodDescriptor RCSP_NEW = MethodDescriptor.ofConstructor(RuntimeConfigSourceProvider.class, String.class); + static final MethodDescriptor RCSF_NEW = MethodDescriptor.ofConstructor(RuntimeConfigSourceFactory.class, String.class); static final MethodDescriptor AL_NEW = MethodDescriptor.ofConstructor(ArrayList.class); static final MethodDescriptor AL_ADD = MethodDescriptor.ofMethod(ArrayList.class, "add", boolean.class, Object.class); @@ -251,28 +262,7 @@ public final class RunTimeConfigurationGenerator { private RunTimeConfigurationGenerator() { } - public static void generate( - final BuildTimeConfigurationReader.ReadResult readResult, - final ClassOutput classOutput, - LaunchMode launchMode, - final Map runTimeDefaults, - final List> additionalTypes, - final List additionalStaticInitConfigSourceProviders, - final List additionalBootstrapConfigSourceProviders) { - - new GenerateOperation.Builder() - .setBuildTimeReadResult(readResult) - .setClassOutput(classOutput) - .setLaunchMode(launchMode) - .setRunTimeDefaults(runTimeDefaults) - .setAdditionalTypes(additionalTypes) - .setAdditionalStaticInitConfigSourceProviders(additionalStaticInitConfigSourceProviders) - .setAdditionalBootstrapConfigSourceProviders(additionalBootstrapConfigSourceProviders) - .build() - .run(); - } - - static final class GenerateOperation implements AutoCloseable { + public static final class GenerateOperation implements AutoCloseable { final boolean devMode; final LaunchMode launchMode; final AccessorFinder accessorFinder; @@ -299,8 +289,13 @@ static final class GenerateOperation implements AutoCloseable { final ResultHandle clinitConfig; final Map> convertersToRegister = new HashMap<>(); final List> additionalTypes; - final List additionalStaticInitConfigSourceProviders; final List additionalBootstrapConfigSourceProviders; + final Set staticConfigSources; + final Set staticConfigSourceProviders; + final Set staticConfigSourceFactories; + final Set runtimeConfigSources; + final Set runtimeConfigSourceProviders; + final Set runtimeConfigSourceFactories; /** * Regular converters organized by type. Each converter is stored in a separate field. Some are used * only at build time, some only at run time, and some at both times. @@ -331,8 +326,13 @@ static final class GenerateOperation implements AutoCloseable { roots = Assert.checkNotNullParam("builder.roots", builder.getBuildTimeReadResult().getAllRoots()); runTimeDefaults = Assert.checkNotNullParam("runTimeDefaults", builder.getRunTimeDefaults()); additionalTypes = Assert.checkNotNullParam("additionalTypes", builder.getAdditionalTypes()); - additionalStaticInitConfigSourceProviders = builder.getAdditionalStaticInitConfigSourceProviders(); additionalBootstrapConfigSourceProviders = builder.getAdditionalBootstrapConfigSourceProviders(); + staticConfigSources = builder.getStaticConfigSources(); + staticConfigSourceProviders = builder.getStaticConfigSourceProviders(); + staticConfigSourceFactories = builder.getStaticConfigSourceFactories(); + runtimeConfigSources = builder.getRuntimeConfigSources(); + runtimeConfigSourceProviders = builder.getRuntimeConfigSourceProviders(); + runtimeConfigSourceFactories = builder.getRuntimeConfigSourceFactories(); cc = ClassCreator.builder().classOutput(classOutput).className(CONFIG_CLASS_NAME).setFinal(true).build(); generateEmptyParsers(cc); // not instantiable @@ -406,11 +406,22 @@ static final class GenerateOperation implements AutoCloseable { // build time defaults clinit.writeArrayValue(array, 1, buildTimeRunTimeDefaultValuesConfigSource); clinit.invokeVirtualMethod(SRCB_WITH_SOURCES, buildTimeBuilder, array); - // add static init sources - for (String providerClass : additionalStaticInitConfigSourceProviders) { - ResultHandle providerInstance = clinit.newInstance(MethodDescriptor.ofConstructor(providerClass)); - clinit.invokeStaticMethod(CU_ADD_SOURCE_PROVIDER, buildTimeBuilder, providerInstance); + // add safe static sources + for (String runtimeConfigSource : staticConfigSources) { + clinit.invokeStaticMethod(CU_ADD_SOURCE_PROVIDER, buildTimeBuilder, + clinit.newInstance(RCS_NEW, clinit.load(runtimeConfigSource))); } + // add safe static source providers + for (String runtimeConfigSourceProvider : staticConfigSourceProviders) { + clinit.invokeStaticMethod(CU_ADD_SOURCE_PROVIDER, buildTimeBuilder, + clinit.newInstance(RCSP_NEW, clinit.load(runtimeConfigSourceProvider))); + } + // add safe static source factories + for (String discoveredConfigSourceFactory : staticConfigSourceFactories) { + clinit.invokeStaticMethod(CU_ADD_SOURCE_FACTORY_PROVIDER, buildTimeBuilder, + clinit.newInstance(RCSF_NEW, clinit.load(discoveredConfigSourceFactory))); + } + clinitConfig = clinit.checkCast(clinit.invokeVirtualMethod(SRCB_BUILD, buildTimeBuilder), SmallRyeConfig.class); @@ -516,7 +527,9 @@ public void run() { } // create the run time config - final ResultHandle runTimeBuilder = readConfig.invokeStaticMethod(CU_CONFIG_BUILDER, readConfig.load(true), + final ResultHandle runTimeBuilder = readConfig.invokeStaticMethod( + CU_CONFIG_BUILDER_WITH_ADD_DISCOVERED_AND_BOOTSRAP, readConfig.load(true), readConfig.load(false), + readConfig.load(false), readConfig.load(launchMode)); // add in our run time only config source provider @@ -633,6 +646,24 @@ public void run() { // (which were generated by the bootstrap config phase - an empty list is passed when there is no bootstrap phase) readConfig.invokeStaticMethod(CU_ADD_SOURCE_PROVIDERS, runTimeBuilder, readConfig.getMethodParam(0)); + // add discovered sources + for (String runtimeConfigSource : runtimeConfigSources) { + readConfig.invokeStaticMethod(CU_ADD_SOURCE_PROVIDER, runTimeBuilder, + readConfig.newInstance(RCS_NEW, readConfig.load(runtimeConfigSource))); + } + + // add discovered source providers + for (String runtimeConfigSourceProvider : runtimeConfigSourceProviders) { + readConfig.invokeStaticMethod(CU_ADD_SOURCE_PROVIDER, runTimeBuilder, + readConfig.newInstance(RCSP_NEW, readConfig.load(runtimeConfigSourceProvider))); + } + + // add discovered source factories + for (String discoveredConfigSourceFactory : runtimeConfigSourceFactories) { + readConfig.invokeStaticMethod(CU_ADD_SOURCE_FACTORY_PROVIDER, runTimeBuilder, + readConfig.newInstance(RCSF_NEW, readConfig.load(discoveredConfigSourceFactory))); + } + ResultHandle bootstrapConfig = null; if (bootstrapConfigSetupNeeded()) { bootstrapConfig = readBootstrapConfig.invokeVirtualMethod(SRCB_BUILD, bootstrapBuilder); @@ -1633,15 +1664,25 @@ public void close() { cc.close(); } - static final class Builder { + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { private LaunchMode launchMode; private ClassOutput classOutput; private BuildTimeConfigurationReader.ReadResult buildTimeReadResult; private Map runTimeDefaults; private List> additionalTypes; - private List additionalStaticInitConfigSourceProviders; private List additionalBootstrapConfigSourceProviders; + private Set staticConfigSources; + private Set staticConfigSourceProviders; + private Set staticConfigSourceFactories; + private Set runtimeConfigSources; + private Set runtimeConfigSourceProviders; + private Set runtimeConfigSourceFactories; + Builder() { } @@ -1649,7 +1690,7 @@ ClassOutput getClassOutput() { return classOutput; } - Builder setClassOutput(final ClassOutput classOutput) { + public Builder setClassOutput(final ClassOutput classOutput) { this.classOutput = classOutput; return this; } @@ -1658,7 +1699,7 @@ BuildTimeConfigurationReader.ReadResult getBuildTimeReadResult() { return buildTimeReadResult; } - Builder setBuildTimeReadResult(final BuildTimeConfigurationReader.ReadResult buildTimeReadResult) { + public Builder setBuildTimeReadResult(final BuildTimeConfigurationReader.ReadResult buildTimeReadResult) { this.buildTimeReadResult = buildTimeReadResult; return this; } @@ -1667,7 +1708,7 @@ Map getRunTimeDefaults() { return runTimeDefaults; } - Builder setRunTimeDefaults(final Map runTimeDefaults) { + public Builder setRunTimeDefaults(final Map runTimeDefaults) { this.runTimeDefaults = runTimeDefaults; return this; } @@ -1676,7 +1717,7 @@ List> getAdditionalTypes() { return additionalTypes; } - Builder setAdditionalTypes(final List> additionalTypes) { + public Builder setAdditionalTypes(final List> additionalTypes) { this.additionalTypes = additionalTypes; return this; } @@ -1690,25 +1731,70 @@ public Builder setLaunchMode(LaunchMode launchMode) { return this; } - List getAdditionalStaticInitConfigSourceProviders() { - return additionalStaticInitConfigSourceProviders; + List getAdditionalBootstrapConfigSourceProviders() { + return additionalBootstrapConfigSourceProviders; } - Builder setAdditionalStaticInitConfigSourceProviders(List additionalStaticInitConfigSourceProviders) { - this.additionalStaticInitConfigSourceProviders = additionalStaticInitConfigSourceProviders; + public Builder setAdditionalBootstrapConfigSourceProviders(List additionalBootstrapConfigSourceProviders) { + this.additionalBootstrapConfigSourceProviders = additionalBootstrapConfigSourceProviders; return this; } - List getAdditionalBootstrapConfigSourceProviders() { - return additionalBootstrapConfigSourceProviders; + Set getStaticConfigSources() { + return staticConfigSources; } - Builder setAdditionalBootstrapConfigSourceProviders(List additionalBootstrapConfigSourceProviders) { - this.additionalBootstrapConfigSourceProviders = additionalBootstrapConfigSourceProviders; + public Builder setStaticConfigSources(final Set staticConfigSources) { + this.staticConfigSources = staticConfigSources; + return this; + } + + Set getStaticConfigSourceProviders() { + return staticConfigSourceProviders; + } + + public Builder setStaticConfigSourceProviders(final Set staticConfigSourceProviders) { + this.staticConfigSourceProviders = staticConfigSourceProviders; + return this; + } + + Set getStaticConfigSourceFactories() { + return staticConfigSourceFactories; + } + + public Builder setStaticConfigSourceFactories(final Set staticConfigSourceFactories) { + this.staticConfigSourceFactories = staticConfigSourceFactories; + return this; + } + + Set getRuntimeConfigSources() { + return runtimeConfigSources; + } + + public Builder setRuntimeConfigSources(final Set runtimeConfigSources) { + this.runtimeConfigSources = runtimeConfigSources; + return this; + } + + Set getRuntimeConfigSourceProviders() { + return runtimeConfigSourceProviders; + } + + public Builder setRuntimeConfigSourceProviders(final Set runtimeConfigSourceProviders) { + this.runtimeConfigSourceProviders = runtimeConfigSourceProviders; + return this; + } + + Set getRuntimeConfigSourceFactories() { + return runtimeConfigSourceFactories; + } + + public Builder setRuntimeConfigSourceFactories(final Set runtimeConfigSourceFactories) { + this.runtimeConfigSourceFactories = runtimeConfigSourceFactories; return this; } - GenerateOperation build() { + public GenerateOperation build() { return new GenerateOperation(this); } } diff --git a/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigBuildSteps.java b/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigBuildSteps.java index 1019d415ea756..2d64454e7298e 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigBuildSteps.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigBuildSteps.java @@ -5,7 +5,6 @@ import java.util.List; import java.util.OptionalInt; import java.util.Set; -import java.util.stream.Collectors; import org.eclipse.microprofile.config.spi.ConfigProviderResolver; import org.eclipse.microprofile.config.spi.ConfigSource; @@ -27,7 +26,6 @@ import io.quarkus.gizmo.MethodDescriptor; import io.quarkus.gizmo.ResultHandle; import io.quarkus.runtime.graal.InetRunTime; -import io.smallrye.config.ConfigSourceFactory; import io.smallrye.config.ConfigSourceInterceptor; import io.smallrye.config.ConfigSourceInterceptorFactory; import io.smallrye.config.ConfigValidator; @@ -82,22 +80,15 @@ void nativeServiceProviders( providerProducer.produce(new ServiceProviderBuildItem(ConfigProviderResolver.class.getName(), SmallRyeConfigProviderResolver.class.getName())); final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - classLoader.getResources(SERVICES_PREFIX + ConfigSourceProvider.class.getName()); for (Class serviceClass : Arrays.asList( - ConfigSource.class, - ConfigSourceProvider.class, Converter.class, ConfigSourceInterceptor.class, ConfigSourceInterceptorFactory.class, - ConfigSourceFactory.class, ConfigValidator.class)) { final String serviceName = serviceClass.getName(); final Set names = ServiceUtil.classNamesNamedIn(classLoader, SERVICES_PREFIX + serviceName); - final List list = names.stream() - // todo: see https://github.com/quarkusio/quarkus/issues/5492 - .filter(s -> !s.startsWith("org.jboss.resteasy.microprofile.config.")).collect(Collectors.toList()); - if (!list.isEmpty()) { - providerProducer.produce(new ServiceProviderBuildItem(serviceName, list)); + if (!names.isEmpty()) { + providerProducer.produce(new ServiceProviderBuildItem(serviceName, names)); } } } 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 95bacd6703f9c..2063e8238ea81 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 @@ -1,5 +1,10 @@ package io.quarkus.deployment.steps; +import static io.quarkus.deployment.steps.ConfigBuildSteps.SERVICES_PREFIX; +import static io.quarkus.deployment.util.ServiceUtil.classNamesNamedIn; +import static java.util.stream.Collectors.toList; + +import java.io.IOException; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collections; @@ -13,6 +18,8 @@ import org.eclipse.microprofile.config.Config; import org.eclipse.microprofile.config.ConfigProvider; +import org.eclipse.microprofile.config.spi.ConfigSource; +import org.eclipse.microprofile.config.spi.ConfigSourceProvider; import io.quarkus.deployment.GeneratedClassGizmoAdaptor; import io.quarkus.deployment.IsNormal; @@ -21,14 +28,16 @@ import io.quarkus.deployment.annotations.ExecutionTime; import io.quarkus.deployment.annotations.Record; import io.quarkus.deployment.builditem.AdditionalBootstrapConfigSourceProviderBuildItem; -import io.quarkus.deployment.builditem.AdditionalStaticInitConfigSourceProviderBuildItem; import io.quarkus.deployment.builditem.ConfigurationBuildItem; import io.quarkus.deployment.builditem.ConfigurationTypeBuildItem; import io.quarkus.deployment.builditem.GeneratedClassBuildItem; import io.quarkus.deployment.builditem.LaunchModeBuildItem; import io.quarkus.deployment.builditem.LiveReloadBuildItem; import io.quarkus.deployment.builditem.RunTimeConfigurationDefaultBuildItem; +import io.quarkus.deployment.builditem.StaticInitConfigSourceFactoryBuildItem; +import io.quarkus.deployment.builditem.StaticInitConfigSourceProviderBuildItem; import io.quarkus.deployment.builditem.SuppressNonRuntimeConfigChangedWarningBuildItem; +import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem; import io.quarkus.deployment.configuration.BuildTimeConfigurationReader; import io.quarkus.deployment.configuration.RunTimeConfigurationGenerator; import io.quarkus.deployment.configuration.definition.ClassDefinition; @@ -40,50 +49,79 @@ import io.quarkus.runtime.configuration.ConfigChangeRecorder; import io.quarkus.runtime.configuration.ConfigurationRuntimeConfig; import io.quarkus.runtime.configuration.RuntimeOverrideConfigSource; +import io.quarkus.runtime.configuration.StaticInitSafe; +import io.smallrye.config.ConfigSourceFactory; +import io.smallrye.config.PropertiesLocationConfigSourceFactory; public class ConfigGenerationBuildStep { + @BuildStep + void staticInitSources( + BuildProducer staticInitConfigSourceProviderBuildItem, + BuildProducer staticInitConfigSourceFactoryBuildItem) { + + staticInitConfigSourceFactoryBuildItem.produce(new StaticInitConfigSourceFactoryBuildItem( + PropertiesLocationConfigSourceFactory.class.getName())); + } + /** * Generate the Config class that instantiates MP Config and holds all the config objects */ @BuildStep - void generateConfigClass(ConfigurationBuildItem configItem, List runTimeDefaults, + void generateConfigClass( + ConfigurationBuildItem configItem, + List runTimeDefaults, List typeItems, LaunchModeBuildItem launchModeBuildItem, BuildProducer generatedClass, + BuildProducer reflectiveClass, LiveReloadBuildItem liveReloadBuildItem, - List additionalStaticInitConfigSourceProviders, - List additionalBootstrapConfigSourceProviders) { + List additionalBootstrapConfigSourceProviders, + List staticInitConfigSourceProviders, + List staticInitConfigSourceFactories) + throws IOException { + if (liveReloadBuildItem.isLiveReload()) { return; } - BuildTimeConfigurationReader.ReadResult readResult = configItem.getReadResult(); + Map defaults = new HashMap<>(); for (RunTimeConfigurationDefaultBuildItem item : runTimeDefaults) { if (defaults.putIfAbsent(item.getKey(), item.getValue()) != null) { throw new IllegalStateException("More than one default value for " + item.getKey() + " was produced"); } } - List> additionalConfigTypes = typeItems.stream().map(ConfigurationTypeBuildItem::getValueType) - .collect(Collectors.toList()); - - ClassOutput classOutput = new GeneratedClassGizmoAdaptor(generatedClass, false); - RunTimeConfigurationGenerator.generate(readResult, classOutput, - launchModeBuildItem.getLaunchMode(), defaults, additionalConfigTypes, - getAdditionalStaticInitConfigSourceProviders(additionalStaticInitConfigSourceProviders), - getAdditionalBootstrapConfigSourceProviders(additionalBootstrapConfigSourceProviders)); - } - private List getAdditionalStaticInitConfigSourceProviders( - List additionalStaticInitConfigSourceProviders) { - if (additionalStaticInitConfigSourceProviders.isEmpty()) { - return Collections.emptyList(); - } - List result = new ArrayList<>(additionalStaticInitConfigSourceProviders.size()); - for (AdditionalStaticInitConfigSourceProviderBuildItem provider : additionalStaticInitConfigSourceProviders) { - result.add(provider.getProviderClassName()); - } - return result; + Set discoveredConfigSources = discoverService(ConfigSource.class, reflectiveClass); + Set discoveredConfigSourceProviders = discoverService(ConfigSourceProvider.class, reflectiveClass); + Set discoveredConfigSourceFactories = discoverService(ConfigSourceFactory.class, reflectiveClass); + + Set staticConfigSourceProviders = new HashSet<>(); + staticConfigSourceProviders.addAll(staticSafeServices(discoveredConfigSourceProviders)); + staticConfigSourceProviders.addAll(staticInitConfigSourceProviders.stream() + .map(StaticInitConfigSourceProviderBuildItem::getProviderClassName).collect(Collectors.toSet())); + Set staticConfigSourceFactories = new HashSet<>(); + staticConfigSourceFactories.addAll(staticSafeServices(discoveredConfigSourceFactories)); + staticConfigSourceFactories.addAll(staticInitConfigSourceFactories.stream() + .map(StaticInitConfigSourceFactoryBuildItem::getFactoryClassName).collect(Collectors.toSet())); + + RunTimeConfigurationGenerator.GenerateOperation + .builder() + .setBuildTimeReadResult(configItem.getReadResult()) + .setClassOutput(new GeneratedClassGizmoAdaptor(generatedClass, false)) + .setLaunchMode(launchModeBuildItem.getLaunchMode()) + .setRunTimeDefaults(defaults) + .setAdditionalTypes(typeItems.stream().map(ConfigurationTypeBuildItem::getValueType).collect(toList())) + .setAdditionalBootstrapConfigSourceProviders( + getAdditionalBootstrapConfigSourceProviders(additionalBootstrapConfigSourceProviders)) + .setStaticConfigSources(staticSafeServices(discoveredConfigSources)) + .setStaticConfigSourceProviders(staticConfigSourceProviders) + .setStaticConfigSourceFactories(staticConfigSourceFactories) + .setRuntimeConfigSources(discoveredConfigSources) + .setRuntimeConfigSourceProviders(discoveredConfigSourceProviders) + .setRuntimeConfigSourceFactories(discoveredConfigSourceFactories) + .build() + .run(); } private List getAdditionalBootstrapConfigSourceProviders( @@ -167,4 +205,32 @@ private void handleMembers(Config config, Map values, Iterable discoverService( + Class serviceClass, + BuildProducer reflectiveClass) throws IOException { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + Set services = new HashSet<>(); + for (String service : classNamesNamedIn(classLoader, SERVICES_PREFIX + serviceClass.getName())) { + services.add(service); + reflectiveClass.produce(new ReflectiveClassBuildItem(true, false, false, service)); + } + return services; + } + + private static Set staticSafeServices(Set services) { + // TODO - Replace with Jandex? The issue is that the sources may not be in the index... + ClassLoader classloader = Thread.currentThread().getContextClassLoader(); + Set staticSafe = new HashSet<>(); + for (String service : services) { + try { + Class serviceClass = classloader.loadClass(service); + if (serviceClass.isAnnotationPresent(StaticInitSafe.class)) { + staticSafe.add(service); + } + } catch (ClassNotFoundException e) { + // Ignore + } + } + return staticSafe; + } } diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigSourceFactoryProvider.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigSourceFactoryProvider.java new file mode 100644 index 0000000000000..15090cf88cba0 --- /dev/null +++ b/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigSourceFactoryProvider.java @@ -0,0 +1,7 @@ +package io.quarkus.runtime.configuration; + +import io.smallrye.config.ConfigSourceFactory; + +public interface ConfigSourceFactoryProvider { + ConfigSourceFactory getConfigSourceFactory(final ClassLoader forClassLoader); +} diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigUtils.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigUtils.java index 306b7a5daccfb..c9d2c35e3088c 100644 --- a/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigUtils.java +++ b/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigUtils.java @@ -187,6 +187,10 @@ public static void addSourceProviders(SmallRyeConfigBuilder builder, Collection< } } + public static void addSourceFactoryProvider(SmallRyeConfigBuilder builder, ConfigSourceFactoryProvider provider) { + builder.withSources(provider.getConfigSourceFactory(Thread.currentThread().getContextClassLoader())); + } + /** * Checks if a property is present in the current Configuration. * diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/RuntimeConfigSource.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/RuntimeConfigSource.java new file mode 100644 index 0000000000000..eeb2f1117618f --- /dev/null +++ b/core/runtime/src/main/java/io/quarkus/runtime/configuration/RuntimeConfigSource.java @@ -0,0 +1,27 @@ +package io.quarkus.runtime.configuration; + +import java.lang.reflect.InvocationTargetException; +import java.util.Collections; + +import org.eclipse.microprofile.config.spi.ConfigSource; +import org.eclipse.microprofile.config.spi.ConfigSourceProvider; + +public class RuntimeConfigSource implements ConfigSourceProvider { + private final String configSourceClassName; + + public RuntimeConfigSource(final String configSourceClassName) { + this.configSourceClassName = configSourceClassName; + } + + @Override + public Iterable getConfigSources(final ClassLoader forClassLoader) { + try { + Class configSourceClass = (Class) forClassLoader.loadClass(configSourceClassName); + ConfigSource configSource = configSourceClass.getDeclaredConstructor().newInstance(); + return Collections.singleton(configSource); + } catch (ClassNotFoundException | InstantiationException | InvocationTargetException | NoSuchMethodException + | IllegalAccessException e) { + throw new ConfigurationException(e); + } + } +} diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/RuntimeConfigSourceFactory.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/RuntimeConfigSourceFactory.java new file mode 100644 index 0000000000000..355f22edd5baf --- /dev/null +++ b/core/runtime/src/main/java/io/quarkus/runtime/configuration/RuntimeConfigSourceFactory.java @@ -0,0 +1,25 @@ +package io.quarkus.runtime.configuration; + +import java.lang.reflect.InvocationTargetException; + +import io.smallrye.config.ConfigSourceFactory; + +public class RuntimeConfigSourceFactory implements ConfigSourceFactoryProvider { + private final String configSourceFactoryClassName; + + public RuntimeConfigSourceFactory(final String configSourceFactoryClassName) { + this.configSourceFactoryClassName = configSourceFactoryClassName; + } + + @Override + public ConfigSourceFactory getConfigSourceFactory(final ClassLoader forClassLoader) { + try { + Class configSourceFactoryClass = (Class) forClassLoader + .loadClass(configSourceFactoryClassName); + return configSourceFactoryClass.getDeclaredConstructor().newInstance(); + } catch (ClassNotFoundException | InstantiationException | InvocationTargetException | NoSuchMethodException + | IllegalAccessException e) { + throw new ConfigurationException(e); + } + } +} diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/RuntimeConfigSourceProvider.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/RuntimeConfigSourceProvider.java new file mode 100644 index 0000000000000..54e6e33290dee --- /dev/null +++ b/core/runtime/src/main/java/io/quarkus/runtime/configuration/RuntimeConfigSourceProvider.java @@ -0,0 +1,27 @@ +package io.quarkus.runtime.configuration; + +import java.lang.reflect.InvocationTargetException; + +import org.eclipse.microprofile.config.spi.ConfigSource; +import org.eclipse.microprofile.config.spi.ConfigSourceProvider; + +public class RuntimeConfigSourceProvider implements ConfigSourceProvider { + private final String configSourceProviderClassName; + + public RuntimeConfigSourceProvider(final String configSourceProviderClassName) { + this.configSourceProviderClassName = configSourceProviderClassName; + } + + @Override + public Iterable getConfigSources(final ClassLoader forClassLoader) { + try { + Class configSourceProviderClass = (Class) forClassLoader + .loadClass(configSourceProviderClassName); + ConfigSourceProvider configSourceProvider = configSourceProviderClass.getDeclaredConstructor().newInstance(); + return configSourceProvider.getConfigSources(forClassLoader); + } catch (ClassNotFoundException | InstantiationException | InvocationTargetException | NoSuchMethodException + | IllegalAccessException e) { + throw new ConfigurationException(e); + } + } +} diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/StaticInitSafe.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/StaticInitSafe.java new file mode 100644 index 0000000000000..5589c4f5c3630 --- /dev/null +++ b/core/runtime/src/main/java/io/quarkus/runtime/configuration/StaticInitSafe.java @@ -0,0 +1,22 @@ +package io.quarkus.runtime.configuration; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * Used to mark a ConfigSource, ConfigSourceProvider or ConfigSourceFactory as safe to be initialized during STATIC + * INIT. + * + * This is required, because some Configs may not be suited to be executed at static init. Consider a Config that + * requires database access. Since Config is the first thing being initialized, the database services are not available + * yet so the ConfigSource is unusable. + */ +@Target(TYPE) +@Retention(RUNTIME) +@Documented +public @interface StaticInitSafe { +} diff --git a/core/test-extension/deployment/src/test/java/io/quarkus/extest/StaticInitSourcesTest.java b/core/test-extension/deployment/src/test/java/io/quarkus/extest/StaticInitSourcesTest.java new file mode 100644 index 0000000000000..3d0ab90ff63b9 --- /dev/null +++ b/core/test-extension/deployment/src/test/java/io/quarkus/extest/StaticInitSourcesTest.java @@ -0,0 +1,30 @@ +package io.quarkus.extest; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.extest.runtime.config.StaticInitNotSafeConfigSource; +import io.quarkus.extest.runtime.config.StaticInitSafeConfigSource; +import io.quarkus.test.QuarkusUnitTest; + +public class StaticInitSourcesTest { + @RegisterExtension + static final QuarkusUnitTest TEST = new QuarkusUnitTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) + .addClasses(ConfiguredBean.class) + // Don't change this to types, because of classloader class cast exception. + .addAsServiceProvider("org.eclipse.microprofile.config.spi.ConfigSource", + StaticInitSafeConfigSource.class.getName(), + StaticInitNotSafeConfigSource.class.getName()) + .addAsResource("application.properties")); + + @Test + void staticInitSources() { + assertEquals(2, StaticInitSafeConfigSource.counter.get()); + assertEquals(1, StaticInitNotSafeConfigSource.counter.get()); + } +} diff --git a/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/config/StaticInitNotSafeConfigSource.java b/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/config/StaticInitNotSafeConfigSource.java new file mode 100644 index 0000000000000..91373ef22693a --- /dev/null +++ b/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/config/StaticInitNotSafeConfigSource.java @@ -0,0 +1,15 @@ +package io.quarkus.extest.runtime.config; + +import java.util.Collections; +import java.util.concurrent.atomic.AtomicInteger; + +import io.smallrye.config.common.MapBackedConfigSource; + +public class StaticInitNotSafeConfigSource extends MapBackedConfigSource { + public static AtomicInteger counter = new AtomicInteger(0); + + public StaticInitNotSafeConfigSource() { + super(StaticInitNotSafeConfigSource.class.getName(), Collections.emptyMap()); + counter.incrementAndGet(); + } +} diff --git a/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/config/StaticInitSafeConfigSource.java b/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/config/StaticInitSafeConfigSource.java new file mode 100644 index 0000000000000..e5d1c081fe818 --- /dev/null +++ b/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/config/StaticInitSafeConfigSource.java @@ -0,0 +1,17 @@ +package io.quarkus.extest.runtime.config; + +import java.util.Collections; +import java.util.concurrent.atomic.AtomicInteger; + +import io.quarkus.runtime.configuration.StaticInitSafe; +import io.smallrye.config.common.MapBackedConfigSource; + +@StaticInitSafe +public class StaticInitSafeConfigSource extends MapBackedConfigSource { + public static AtomicInteger counter = new AtomicInteger(0); + + public StaticInitSafeConfigSource() { + super(StaticInitSafeConfigSource.class.getName(), Collections.emptyMap()); + counter.incrementAndGet(); + } +} diff --git a/docs/src/main/asciidoc/writing-extensions.adoc b/docs/src/main/asciidoc/writing-extensions.adoc index 90f7428393633..dcee4daca0c2e 100644 --- a/docs/src/main/asciidoc/writing-extensions.adoc +++ b/docs/src/main/asciidoc/writing-extensions.adoc @@ -71,7 +71,7 @@ But many properties like enable caching or setting the JDBC driver can safely re ==== Static Init Config -If the extension provides additional Config Sources and if these are required during Static Init, these must be registered with `AdditionalStaticInitConfigSourceProviderBuildItem`. Configuration in Static Init does not scan for additional sources to avoid double initialization at application startup time. +If the extension provides additional Config Sources and if these are required during Static Init, these must be registered with `StaticInitConfigSourceProviderBuildItem`. Configuration in Static Init does not scan for additional sources to avoid double initialization at application startup time. //// === API diff --git a/extensions/resteasy-classic/resteasy-common/deployment/src/main/java/io/quarkus/resteasy/common/deployment/ResteasyCommonProcessor.java b/extensions/resteasy-classic/resteasy-common/deployment/src/main/java/io/quarkus/resteasy/common/deployment/ResteasyCommonProcessor.java index d50a5d1141ab8..caca8b3060f5f 100644 --- a/extensions/resteasy-classic/resteasy-common/deployment/src/main/java/io/quarkus/resteasy/common/deployment/ResteasyCommonProcessor.java +++ b/extensions/resteasy-classic/resteasy-common/deployment/src/main/java/io/quarkus/resteasy/common/deployment/ResteasyCommonProcessor.java @@ -32,6 +32,9 @@ import org.jboss.jandex.Type; import org.jboss.logging.Logger; import org.jboss.resteasy.core.MediaTypeMap; +import org.jboss.resteasy.microprofile.config.FilterConfigSourceImpl; +import org.jboss.resteasy.microprofile.config.ServletConfigSourceImpl; +import org.jboss.resteasy.microprofile.config.ServletContextConfigSourceImpl; import org.jboss.resteasy.plugins.interceptors.AcceptEncodingGZIPFilter; import org.jboss.resteasy.plugins.interceptors.GZIPDecodingInterceptor; import org.jboss.resteasy.plugins.interceptors.GZIPEncodingInterceptor; @@ -50,8 +53,8 @@ import io.quarkus.deployment.annotations.BuildStep; import io.quarkus.deployment.annotations.Consume; import io.quarkus.deployment.annotations.Record; -import io.quarkus.deployment.builditem.AdditionalStaticInitConfigSourceProviderBuildItem; import io.quarkus.deployment.builditem.CombinedIndexBuildItem; +import io.quarkus.deployment.builditem.StaticInitConfigSourceProviderBuildItem; import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem; import io.quarkus.deployment.util.ServiceUtil; import io.quarkus.resteasy.common.runtime.ResteasyInjectorFactoryRecorder; @@ -122,9 +125,22 @@ public static final class ResteasyCommonConfigGzip { } @BuildStep - void initConfigSourceProvider(BuildProducer initConfigSourceProvider) { + void addStaticInitConfigSourceProvider( + Capabilities capabilities, + BuildProducer initConfigSourceProvider, + BuildProducer reflectiveClass) { + + if (!capabilities.isCapabilityWithPrefixPresent(Capability.SERVLET)) { + return; + } + initConfigSourceProvider.produce( - new AdditionalStaticInitConfigSourceProviderBuildItem(ResteasyConfigSourceProvider.class.getName())); + new StaticInitConfigSourceProviderBuildItem(ResteasyConfigSourceProvider.class.getName())); + + reflectiveClass.produce(new ReflectiveClassBuildItem(false, false, + ServletConfigSourceImpl.class, + ServletContextConfigSourceImpl.class, + FilterConfigSourceImpl.class)); } @BuildStep diff --git a/extensions/resteasy-classic/resteasy-common/runtime/src/main/java/io/quarkus/resteasy/common/runtime/graal/ServletMissing.java b/extensions/resteasy-classic/resteasy-common/runtime/src/main/java/io/quarkus/resteasy/common/runtime/graal/ServletMissing.java new file mode 100644 index 0000000000000..78dc0fd549dd2 --- /dev/null +++ b/extensions/resteasy-classic/resteasy-common/runtime/src/main/java/io/quarkus/resteasy/common/runtime/graal/ServletMissing.java @@ -0,0 +1,38 @@ +package io.quarkus.resteasy.common.runtime.graal; + +import java.util.function.BooleanSupplier; + +/** + * Checks if servlet classes are available in the classpath and a suitable implementation. This is required because + * ConfigSource's provided by RESTEasy, need the servlet classes to function properly. If these classes are not found, + * we rewrite the sources to remove any references to the servlet classes and the internal RESTEasy sources in native + * mode. + * + * The offending RESTEasy sources are: + * {@link org.jboss.resteasy.microprofile.config.ServletConfigSource} + * {@link org.jboss.resteasy.microprofile.config.ServletContextConfigSource} + * {@link org.jboss.resteasy.microprofile.config.FilterConfigSource} + * + * The main instances sources are still part of the Config instance, but without the backing implementations, the source + * do not return any values. + * + * Ideally, this should be fixed in RESTEasy. + * + * See https://github.com/quarkusio/quarkus/issues/5492 + * See https://github.com/quarkusio/quarkus/issues/9086 + * See https://github.com/quarkusio/quarkus/issues/14876 + */ +public final class ServletMissing implements BooleanSupplier { + @Override + public boolean getAsBoolean() { + try { + Class.forName("javax.servlet.ServletConfig"); + Class.forName("javax.servlet.ServletContext"); + Class.forName("javax.servlet.FilterConfig"); + Class.forName("io.quarkus.undertow.runtime.UndertowDeploymentRecorder"); + return false; + } catch (ClassNotFoundException e) { + return true; + } + } +} diff --git a/extensions/resteasy-classic/resteasy-common/runtime/src/main/java/io/quarkus/resteasy/common/runtime/graal/Target_org_jboss_resteasy_microprofile_config_FilterConfigSource.java b/extensions/resteasy-classic/resteasy-common/runtime/src/main/java/io/quarkus/resteasy/common/runtime/graal/Target_org_jboss_resteasy_microprofile_config_FilterConfigSource.java new file mode 100644 index 0000000000000..e148e46d68700 --- /dev/null +++ b/extensions/resteasy-classic/resteasy-common/runtime/src/main/java/io/quarkus/resteasy/common/runtime/graal/Target_org_jboss_resteasy_microprofile_config_FilterConfigSource.java @@ -0,0 +1,14 @@ +package io.quarkus.resteasy.common.runtime.graal; + +import com.oracle.svm.core.annotate.Alias; +import com.oracle.svm.core.annotate.RecomputeFieldValue; +import com.oracle.svm.core.annotate.TargetClass; + +@TargetClass(className = "org.jboss.resteasy.microprofile.config.FilterConfigSource", onlyWith = { + ServletMissing.class +}) +final class Target_org_jboss_resteasy_microprofile_config_FilterConfigSource { + @Alias + @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) + private static Class clazz; +} diff --git a/extensions/resteasy-classic/resteasy-common/runtime/src/main/java/io/quarkus/resteasy/common/runtime/graal/Target_org_jboss_resteasy_microprofile_config_ServletConfigSource.java b/extensions/resteasy-classic/resteasy-common/runtime/src/main/java/io/quarkus/resteasy/common/runtime/graal/Target_org_jboss_resteasy_microprofile_config_ServletConfigSource.java new file mode 100644 index 0000000000000..abc36c27bb6a2 --- /dev/null +++ b/extensions/resteasy-classic/resteasy-common/runtime/src/main/java/io/quarkus/resteasy/common/runtime/graal/Target_org_jboss_resteasy_microprofile_config_ServletConfigSource.java @@ -0,0 +1,14 @@ +package io.quarkus.resteasy.common.runtime.graal; + +import com.oracle.svm.core.annotate.Alias; +import com.oracle.svm.core.annotate.RecomputeFieldValue; +import com.oracle.svm.core.annotate.TargetClass; + +@TargetClass(className = "org.jboss.resteasy.microprofile.config.ServletConfigSource", onlyWith = { + ServletMissing.class +}) +final class Target_org_jboss_resteasy_microprofile_config_ServletConfigSource { + @Alias + @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) + private static Class clazz; +} diff --git a/extensions/resteasy-classic/resteasy-common/runtime/src/main/java/io/quarkus/resteasy/common/runtime/graal/Target_org_jboss_resteasy_microprofile_config_ServletContextConfigSource.java b/extensions/resteasy-classic/resteasy-common/runtime/src/main/java/io/quarkus/resteasy/common/runtime/graal/Target_org_jboss_resteasy_microprofile_config_ServletContextConfigSource.java new file mode 100644 index 0000000000000..56f58739cb109 --- /dev/null +++ b/extensions/resteasy-classic/resteasy-common/runtime/src/main/java/io/quarkus/resteasy/common/runtime/graal/Target_org_jboss_resteasy_microprofile_config_ServletContextConfigSource.java @@ -0,0 +1,15 @@ +package io.quarkus.resteasy.common.runtime.graal; + +import com.oracle.svm.core.annotate.Alias; +import com.oracle.svm.core.annotate.RecomputeFieldValue; +import com.oracle.svm.core.annotate.TargetClass; + +@TargetClass(className = "org.jboss.resteasy.microprofile.config.ServletContextConfigSource", onlyWith = { + ServletMissing.class +}) +final class Target_org_jboss_resteasy_microprofile_config_ServletContextConfigSource { + @Alias + @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) + private static Class clazz; + +} diff --git a/extensions/resteasy-classic/resteasy/deployment/src/main/java/io/quarkus/resteasy/deployment/ResteasyServletProcessor.java b/extensions/resteasy-classic/resteasy/deployment/src/main/java/io/quarkus/resteasy/deployment/ResteasyServletProcessor.java index 0508e4e6ffe69..8a2f3435ef55e 100644 --- a/extensions/resteasy-classic/resteasy/deployment/src/main/java/io/quarkus/resteasy/deployment/ResteasyServletProcessor.java +++ b/extensions/resteasy-classic/resteasy/deployment/src/main/java/io/quarkus/resteasy/deployment/ResteasyServletProcessor.java @@ -12,9 +12,6 @@ import org.jboss.logging.Logger; import org.jboss.metadata.web.spec.ServletMappingMetaData; -import org.jboss.resteasy.microprofile.config.FilterConfigSourceImpl; -import org.jboss.resteasy.microprofile.config.ServletConfigSourceImpl; -import org.jboss.resteasy.microprofile.config.ServletContextConfigSourceImpl; import org.jboss.resteasy.plugins.server.servlet.HttpServlet30Dispatcher; import io.quarkus.deployment.Capabilities; @@ -93,17 +90,14 @@ public void build( BuildProducer reflectiveClass, BuildProducer servletInitParameters, Optional servletContextPathBuildItem, - ResteasyInjectionReadyBuildItem resteasyInjectionReady) throws Exception { + ResteasyInjectionReadyBuildItem resteasyInjectionReady) { + if (!capabilities.isPresent(Capability.SERVLET)) { return; } feature.produce(new FeatureBuildItem(Feature.RESTEASY)); if (resteasyServerConfig.isPresent()) { - reflectiveClass.produce(new ReflectiveClassBuildItem(false, false, - ServletConfigSourceImpl.class, - ServletContextConfigSourceImpl.class, - FilterConfigSourceImpl.class)); String path = resteasyServerConfig.get().getPath(); //if JAX-RS is installed at the root location we use a filter, otherwise we use a Servlet and take over the whole mapped path diff --git a/extensions/smallrye-opentracing/runtime/pom.xml b/extensions/smallrye-opentracing/runtime/pom.xml index 7e3e12f9e3dcc..2f0ac129cb1c4 100644 --- a/extensions/smallrye-opentracing/runtime/pom.xml +++ b/extensions/smallrye-opentracing/runtime/pom.xml @@ -80,11 +80,6 @@ jakarta.servlet jakarta.servlet-api - - org.graalvm.nativeimage - svm - provided - diff --git a/extensions/smallrye-opentracing/runtime/src/main/java/io/quarkus/smallrye/opentracing/runtime/graal/Target_org_jboss_resteasy_microprofile_config_FilterConfigSource.java b/extensions/smallrye-opentracing/runtime/src/main/java/io/quarkus/smallrye/opentracing/runtime/graal/Target_org_jboss_resteasy_microprofile_config_FilterConfigSource.java deleted file mode 100644 index 9c107b29340a2..0000000000000 --- a/extensions/smallrye-opentracing/runtime/src/main/java/io/quarkus/smallrye/opentracing/runtime/graal/Target_org_jboss_resteasy_microprofile_config_FilterConfigSource.java +++ /dev/null @@ -1,33 +0,0 @@ -package io.quarkus.smallrye.opentracing.runtime.graal; - -import java.util.function.BooleanSupplier; - -import com.oracle.svm.core.annotate.Alias; -import com.oracle.svm.core.annotate.RecomputeFieldValue; -import com.oracle.svm.core.annotate.TargetClass; - -/** - * see {@link Target_org_jboss_resteasy_microprofile_config_ServletContextConfigSource} - */ -@TargetClass(className = "org.jboss.resteasy.microprofile.config.FilterConfigSource", onlyWith = { - UndertowMissing.class, - Target_org_jboss_resteasy_microprofile_config_FilterConfigSource.FilterConfigSourceIsLoaded.class -}) -final class Target_org_jboss_resteasy_microprofile_config_FilterConfigSource { - @Alias - @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) - private static Class clazz; - - static class FilterConfigSourceIsLoaded implements BooleanSupplier { - - @Override - public boolean getAsBoolean() { - try { - Class.forName("org.jboss.resteasy.microprofile.config.FilterConfigSource"); - return true; - } catch (ClassNotFoundException e) { - return false; - } - } - } -} diff --git a/extensions/smallrye-opentracing/runtime/src/main/java/io/quarkus/smallrye/opentracing/runtime/graal/Target_org_jboss_resteasy_microprofile_config_ServletConfigSource.java b/extensions/smallrye-opentracing/runtime/src/main/java/io/quarkus/smallrye/opentracing/runtime/graal/Target_org_jboss_resteasy_microprofile_config_ServletConfigSource.java deleted file mode 100644 index abe13f70f35da..0000000000000 --- a/extensions/smallrye-opentracing/runtime/src/main/java/io/quarkus/smallrye/opentracing/runtime/graal/Target_org_jboss_resteasy_microprofile_config_ServletConfigSource.java +++ /dev/null @@ -1,33 +0,0 @@ -package io.quarkus.smallrye.opentracing.runtime.graal; - -import java.util.function.BooleanSupplier; - -import com.oracle.svm.core.annotate.Alias; -import com.oracle.svm.core.annotate.RecomputeFieldValue; -import com.oracle.svm.core.annotate.TargetClass; - -/** - * see {@link Target_org_jboss_resteasy_microprofile_config_ServletContextConfigSource} - */ -@TargetClass(className = "org.jboss.resteasy.microprofile.config.ServletConfigSource", onlyWith = { - UndertowMissing.class, - Target_org_jboss_resteasy_microprofile_config_ServletConfigSource.ServletConfigSourceIsLoaded.class, -}) -final class Target_org_jboss_resteasy_microprofile_config_ServletConfigSource { - @Alias - @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) - private static Class clazz; - - static class ServletConfigSourceIsLoaded implements BooleanSupplier { - - @Override - public boolean getAsBoolean() { - try { - Class.forName("org.jboss.resteasy.microprofile.config.ServletConfigSource"); - return true; - } catch (ClassNotFoundException e) { - return false; - } - } - } -} diff --git a/extensions/smallrye-opentracing/runtime/src/main/java/io/quarkus/smallrye/opentracing/runtime/graal/Target_org_jboss_resteasy_microprofile_config_ServletContextConfigSource.java b/extensions/smallrye-opentracing/runtime/src/main/java/io/quarkus/smallrye/opentracing/runtime/graal/Target_org_jboss_resteasy_microprofile_config_ServletContextConfigSource.java deleted file mode 100644 index 8cef4c3d1bbf4..0000000000000 --- a/extensions/smallrye-opentracing/runtime/src/main/java/io/quarkus/smallrye/opentracing/runtime/graal/Target_org_jboss_resteasy_microprofile_config_ServletContextConfigSource.java +++ /dev/null @@ -1,48 +0,0 @@ -package io.quarkus.smallrye.opentracing.runtime.graal; - -import java.util.function.BooleanSupplier; - -import org.jboss.resteasy.microprofile.config.ServletContextConfigSource; -import org.jboss.resteasy.microprofile.config.ServletContextConfigSourceImpl; - -import com.oracle.svm.core.annotate.Alias; -import com.oracle.svm.core.annotate.RecomputeFieldValue; -import com.oracle.svm.core.annotate.TargetClass; - -/** - * We need this class to ensure that {@link ServletContextConfigSourceImpl} - * isn't loaded unless Undertow has been explicitly added. - * - * This is done because the OpenTracing extension depends on javax.servlet which results in - * {@link ServletContextConfigSourceImpl} - * being loaded (due to what {@link ServletContextConfigSource} checks for), which in turns leads to - * GraalVM failing because the class cannot be instantiated. - * - * See https://github.com/quarkusio/quarkus/issues/9086 - * - * Furthermore, we only reference the class by its name as not avoid having GraalVM fail if the class is not on classpath - * at all. - * - * See https://github.com/quarkusio/quarkus/issues/14876 - */ -@TargetClass(className = "org.jboss.resteasy.microprofile.config.ServletContextConfigSource", onlyWith = { - UndertowMissing.class, - Target_org_jboss_resteasy_microprofile_config_ServletContextConfigSource.ServletContextConfigSourceIsLoaded.class -}) -final class Target_org_jboss_resteasy_microprofile_config_ServletContextConfigSource { - @Alias - @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) - private static Class clazz; - - static class ServletContextConfigSourceIsLoaded implements BooleanSupplier { - @Override - public boolean getAsBoolean() { - try { - Class.forName("org.jboss.resteasy.microprofile.config.ServletContextConfigSource"); - return true; - } catch (ClassNotFoundException e) { - return false; - } - } - } -} diff --git a/extensions/smallrye-opentracing/runtime/src/main/java/io/quarkus/smallrye/opentracing/runtime/graal/UndertowMissing.java b/extensions/smallrye-opentracing/runtime/src/main/java/io/quarkus/smallrye/opentracing/runtime/graal/UndertowMissing.java deleted file mode 100644 index 11f3cd079b2c2..0000000000000 --- a/extensions/smallrye-opentracing/runtime/src/main/java/io/quarkus/smallrye/opentracing/runtime/graal/UndertowMissing.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.quarkus.smallrye.opentracing.runtime.graal; - -import java.util.function.BooleanSupplier; - -final class UndertowMissing implements BooleanSupplier { - - @Override - public boolean getAsBoolean() { - try { - Class.forName("io.quarkus.undertow.runtime.UndertowDeploymentRecorder"); - return false; - } catch (ClassNotFoundException e) { - return true; - } - } -} diff --git a/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/ConfigResource.java b/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/ConfigResource.java index 657ffc92c0db9..74b4941812784 100644 --- a/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/ConfigResource.java +++ b/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/ConfigResource.java @@ -23,17 +23,20 @@ public class ConfigResource { @Path("/{name}") public Response configValue(@PathParam("name") final String name) { final io.smallrye.config.ConfigValue configValue = ((SmallRyeConfig) config).getConfigValue(name); - return Response.ok(new ConfigValue(configValue.getName(), configValue.getValue())).build(); + return Response.ok(new ConfigValue(configValue.getName(), configValue.getValue(), configValue.getConfigSourceName())) + .build(); } @RegisterForReflection public static class ConfigValue { final String name; final String value; + final String sourceName; - public ConfigValue(final String name, final String value) { + public ConfigValue(final String name, final String value, final String sourceName) { this.name = name; this.value = value; + this.sourceName = sourceName; } public String getName() { @@ -43,5 +46,9 @@ public String getName() { public String getValue() { return value; } + + public String getSourceName() { + return sourceName; + } } } diff --git a/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/ConfigurableExceptionMapper.java b/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/ConfigurableExceptionMapper.java new file mode 100644 index 0000000000000..ff1f0f1125489 --- /dev/null +++ b/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/ConfigurableExceptionMapper.java @@ -0,0 +1,29 @@ +package io.quarkus.it.smallrye.config; + +import javax.inject.Inject; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; + +import org.eclipse.microprofile.config.inject.ConfigProperty; + +@Provider +public class ConfigurableExceptionMapper + implements ExceptionMapper { + @Inject + @ConfigProperty(name = "exception.message") + String message; + + public ConfigurableExceptionMapper() { + System.out.println("ConfigurableExceptionMapper.ConfigurableExceptionMapper"); + } + + @Override + public Response toResponse(final ConfigurableExceptionMapperException exception) { + return Response.ok().entity(message).build(); + } + + public static class ConfigurableExceptionMapperException extends RuntimeException { + + } +} diff --git a/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/ConfigurableExceptionMapperResource.java b/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/ConfigurableExceptionMapperResource.java new file mode 100644 index 0000000000000..c70a0cd34ca81 --- /dev/null +++ b/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/ConfigurableExceptionMapperResource.java @@ -0,0 +1,16 @@ +package io.quarkus.it.smallrye.config; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +@Path("/exception") +@Produces(MediaType.WILDCARD) +public class ConfigurableExceptionMapperResource { + @GET + public Response get() { + throw new ConfigurableExceptionMapper.ConfigurableExceptionMapperException(); + } +} diff --git a/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/UserConfigSource.java b/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/UserConfigSource.java new file mode 100644 index 0000000000000..cd5d256868aae --- /dev/null +++ b/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/UserConfigSource.java @@ -0,0 +1,22 @@ +package io.quarkus.it.smallrye.config; + +import java.util.HashMap; +import java.util.Map; + +import io.smallrye.config.common.MapBackedConfigSource; + +public class UserConfigSource extends MapBackedConfigSource { + private static final Map USER_CONFIG = new HashMap<>(); + + static { + USER_CONFIG.put("user.config.prop", "1234"); + } + + public UserConfigSource() { + this(USER_CONFIG); + } + + public UserConfigSource(final Map properties) { + super(UserConfigSource.class.getSimpleName(), properties); + } +} diff --git a/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/UserConfigSourceProvider.java b/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/UserConfigSourceProvider.java new file mode 100644 index 0000000000000..86cb24fb0b065 --- /dev/null +++ b/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/UserConfigSourceProvider.java @@ -0,0 +1,17 @@ +package io.quarkus.it.smallrye.config; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.microprofile.config.spi.ConfigSource; +import org.eclipse.microprofile.config.spi.ConfigSourceProvider; + +public class UserConfigSourceProvider implements ConfigSourceProvider { + @Override + public Iterable getConfigSources(final ClassLoader forClassLoader) { + final Map properties = new HashMap<>(); + properties.put("user.config.provider.prop", "1234"); + return Collections.singleton(new UserConfigSource(properties)); + } +} diff --git a/integration-tests/smallrye-config/src/main/resources/META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource b/integration-tests/smallrye-config/src/main/resources/META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource new file mode 100644 index 0000000000000..d61427d065058 --- /dev/null +++ b/integration-tests/smallrye-config/src/main/resources/META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource @@ -0,0 +1 @@ +io.quarkus.it.smallrye.config.UserConfigSource diff --git a/integration-tests/smallrye-config/src/main/resources/META-INF/services/org.eclipse.microprofile.config.spi.ConfigSourceProvider b/integration-tests/smallrye-config/src/main/resources/META-INF/services/org.eclipse.microprofile.config.spi.ConfigSourceProvider new file mode 100644 index 0000000000000..fda7aefad10c6 --- /dev/null +++ b/integration-tests/smallrye-config/src/main/resources/META-INF/services/org.eclipse.microprofile.config.spi.ConfigSourceProvider @@ -0,0 +1 @@ +io.quarkus.it.smallrye.config.UserConfigSourceProvider diff --git a/integration-tests/smallrye-config/src/main/resources/config.properties b/integration-tests/smallrye-config/src/main/resources/config.properties index fc031ecfd4767..a057d5062f54c 100644 --- a/integration-tests/smallrye-config/src/main/resources/config.properties +++ b/integration-tests/smallrye-config/src/main/resources/config.properties @@ -1 +1,3 @@ config.properties=1234 + +exception.message=This is an exception! diff --git a/integration-tests/smallrye-config/src/main/resources/fallback.properties b/integration-tests/smallrye-config/src/main/resources/fallback.properties index a7903ceca7189..5403f0593c38c 100644 --- a/integration-tests/smallrye-config/src/main/resources/fallback.properties +++ b/integration-tests/smallrye-config/src/main/resources/fallback.properties @@ -1 +1,3 @@ locations.fallback=1234 + +exception.message=This is an exception! diff --git a/integration-tests/smallrye-config/src/main/resources/test-profile.properties b/integration-tests/smallrye-config/src/main/resources/test-profile.properties index ad05d5b34bc4c..bcaec8b63ed77 100644 --- a/integration-tests/smallrye-config/src/main/resources/test-profile.properties +++ b/integration-tests/smallrye-config/src/main/resources/test-profile.properties @@ -1 +1,3 @@ test.profile.main=main + +exception.message=This is an exception! diff --git a/integration-tests/smallrye-config/src/test/java/io/quarkus/it/smallrye/config/ConfigurableExceptionMapperIT.java b/integration-tests/smallrye-config/src/test/java/io/quarkus/it/smallrye/config/ConfigurableExceptionMapperIT.java new file mode 100644 index 0000000000000..be233d353494b --- /dev/null +++ b/integration-tests/smallrye-config/src/test/java/io/quarkus/it/smallrye/config/ConfigurableExceptionMapperIT.java @@ -0,0 +1,7 @@ +package io.quarkus.it.smallrye.config; + +import io.quarkus.test.junit.NativeImageTest; + +@NativeImageTest +public class ConfigurableExceptionMapperIT extends ConfigurableExceptionMapperTest { +} diff --git a/integration-tests/smallrye-config/src/test/java/io/quarkus/it/smallrye/config/ConfigurableExceptionMapperTest.java b/integration-tests/smallrye-config/src/test/java/io/quarkus/it/smallrye/config/ConfigurableExceptionMapperTest.java new file mode 100644 index 0000000000000..62682b8a21698 --- /dev/null +++ b/integration-tests/smallrye-config/src/test/java/io/quarkus/it/smallrye/config/ConfigurableExceptionMapperTest.java @@ -0,0 +1,21 @@ +package io.quarkus.it.smallrye.config; + +import static io.restassured.RestAssured.given; +import static javax.ws.rs.core.Response.Status.OK; +import static org.hamcrest.Matchers.equalTo; + +import org.junit.jupiter.api.Test; + +import io.quarkus.test.junit.QuarkusTest; + +@QuarkusTest +public class ConfigurableExceptionMapperTest { + @Test + void exception() { + given() + .get("/exception") + .then() + .statusCode(OK.getStatusCode()) + .body(equalTo("This is an exception!")); + } +} diff --git a/integration-tests/smallrye-config/src/test/java/io/quarkus/it/smallrye/config/SmallRyeConfigTest.java b/integration-tests/smallrye-config/src/test/java/io/quarkus/it/smallrye/config/SmallRyeConfigTest.java index b96d22f33ae21..ccdb2d4cbf3a0 100644 --- a/integration-tests/smallrye-config/src/test/java/io/quarkus/it/smallrye/config/SmallRyeConfigTest.java +++ b/integration-tests/smallrye-config/src/test/java/io/quarkus/it/smallrye/config/SmallRyeConfigTest.java @@ -81,4 +81,21 @@ void externalConfig() { .statusCode(OK.getStatusCode()) .body("value", equalTo("1234")); } + + @Test + void userConfig() { + given() + .get("/config/{name}", "user.config.prop") + .then() + .statusCode(OK.getStatusCode()) + .body("value", equalTo("1234")) + .body("sourceName", equalTo("UserConfigSource")); + + given() + .get("/config/{name}", "user.config.provider.prop") + .then() + .statusCode(OK.getStatusCode()) + .body("value", equalTo("1234")) + .body("sourceName", equalTo("UserConfigSource")); + } }