From f159dece7e189e91f82ece9738f8fc262921d296 Mon Sep 17 00:00:00 2001 From: Stuart Douglas Date: Wed, 28 Jul 2021 14:16:02 +1000 Subject: [PATCH] RuntimeConfigDefault changes ignored on restart Fixes #17069 --- .../RunTimeConfigurationGenerator.java | 40 +++++-------------- .../steps/ConfigGenerationBuildStep.java | 26 +++++++----- ...hangeRecorder.java => ConfigRecorder.java} | 19 ++++++++- 3 files changed, 41 insertions(+), 44 deletions(-) rename core/runtime/src/main/java/io/quarkus/runtime/configuration/{ConfigChangeRecorder.java => ConfigRecorder.java} (72%) 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 ed359f5e11c2f..3124ddfb27c65 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 @@ -263,7 +263,6 @@ private RunTimeConfigurationGenerator() { } public static final class GenerateOperation implements AutoCloseable { - final boolean devMode; final LaunchMode launchMode; final AccessorFinder accessorFinder; final ClassOutput classOutput; @@ -281,8 +280,6 @@ public static final class GenerateOperation implements AutoCloseable { // default values given in the build configuration final Map specifiedRunTimeDefaultValues; final Map buildTimeRunTimeVisibleValues; - // default values produced by extensions via build item - final Map runTimeDefaults; final Map enclosingMemberMethods = new HashMap<>(); final Map, MethodDescriptor> groupInitMethods = new HashMap<>(); final Map, FieldDescriptor> configRootsByType = new HashMap<>(); @@ -315,7 +312,6 @@ public static final class GenerateOperation implements AutoCloseable { GenerateOperation(Builder builder) { this.launchMode = builder.launchMode; - this.devMode = builder.launchMode == LaunchMode.DEVELOPMENT; final BuildTimeConfigurationReader.ReadResult buildTimeReadResult = builder.buildTimeReadResult; buildTimeConfigResult = Assert.checkNotNullParam("buildTimeReadResult", buildTimeReadResult); specifiedRunTimeDefaultValues = Assert.checkNotNullParam("specifiedRunTimeDefaultValues", @@ -324,7 +320,6 @@ public static final class GenerateOperation implements AutoCloseable { buildTimeReadResult.getBuildTimeRunTimeVisibleValues()); classOutput = Assert.checkNotNullParam("classOutput", builder.getClassOutput()); roots = Assert.checkNotNullParam("builder.roots", builder.getBuildTimeReadResult().getAllRoots()); - runTimeDefaults = Assert.checkNotNullParam("runTimeDefaults", builder.getRunTimeDefaults()); additionalTypes = Assert.checkNotNullParam("additionalTypes", builder.getAdditionalTypes()); additionalBootstrapConfigSourceProviders = builder.getAdditionalBootstrapConfigSourceProviders(); staticConfigSources = builder.getStaticConfigSources(); @@ -341,7 +336,7 @@ public static final class GenerateOperation implements AutoCloseable { mc.invokeSpecialMethod(MethodDescriptor.ofConstructor(Object.class), mc.getThis()); mc.returnValue(null); } - if (devMode) { + if (launchMode.isDevOrTest()) { reinit = cc.getMethodCreator(REINIT); reinit.setModifiers(Opcodes.ACC_STATIC | Opcodes.ACC_PUBLIC); } else { @@ -458,7 +453,7 @@ public void run() { // make the build time config global until we read the run time config - // at run time (when we're ready) we update the factory and then release the build time config installConfiguration(clinitConfig, clinit); - if (devMode) { + if (launchMode.isDevOrTest()) { final ResultHandle buildTimeRunTimeDefaultValuesConfigSource = reinit .readStaticField(C_BUILD_TIME_RUN_TIME_DEFAULTS_CONFIG_SOURCE); // create the map for build time config source @@ -536,10 +531,10 @@ public void run() { readConfig.invokeStaticMethod(CU_ADD_SOURCE_PROVIDER, runTimeBuilder, readConfig.newInstance( MethodDescriptor.ofConstructor("io.quarkus.runtime.generated.ConfigSourceProviderImpl"))); - // create the map for run time specified values config source final ResultHandle specifiedRunTimeValues = clinit.newInstance(HM_NEW); - if (!devMode) { - //we don't need these in devmode + if (!launchMode.isDevOrTest()) { + // create the map for run time specified values config source + //we don't need these in dev/test mode //including it would just cache the first values //but these can already just be read directly, as we are in the same JVM for (Map.Entry entry : specifiedRunTimeDefaultValues.entrySet()) { @@ -547,17 +542,10 @@ public void run() { clinit.load(entry.getValue())); } } - for (Map.Entry entry : runTimeDefaults.entrySet()) { - if (!specifiedRunTimeDefaultValues.containsKey(entry.getKey())) { - // only add entry if the user didn't override it - clinit.invokeVirtualMethod(HM_PUT, specifiedRunTimeValues, clinit.load(entry.getKey()), - clinit.load(entry.getValue())); - } - } final ResultHandle specifiedRunTimeSource = clinit.newInstance(PCS_NEW, specifiedRunTimeValues, clinit.load("Specified default values"), clinit.load(Integer.MIN_VALUE + 100)); cc.getFieldCreator(C_SPECIFIED_RUN_TIME_CONFIG_SOURCE) - .setModifiers(Opcodes.ACC_STATIC | (devMode ? Opcodes.ACC_VOLATILE : Opcodes.ACC_FINAL)); + .setModifiers(Opcodes.ACC_STATIC | Opcodes.ACC_FINAL); clinit.writeStaticField(C_SPECIFIED_RUN_TIME_CONFIG_SOURCE, specifiedRunTimeSource); // add in the custom sources that bootstrap config needs @@ -704,7 +692,7 @@ public void run() { // config root field is volatile in dev mode, final otherwise; we initialize it from clinit, and readConfig in dev mode cc.getFieldCreator(rootFieldDescriptor) .setModifiers(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC - | (devMode ? Opcodes.ACC_VOLATILE : Opcodes.ACC_FINAL)); + | (launchMode.isDevOrTest() ? Opcodes.ACC_VOLATILE : Opcodes.ACC_FINAL)); // construct instance in ResultHandle instance; @@ -724,7 +712,7 @@ public void run() { } clinit.invokeStaticMethod(initGroup, clinitConfig, clinitNameBuilder, instance); clinit.invokeVirtualMethod(SB_SET_LENGTH, clinitNameBuilder, clInitOldLen); - if (devMode) { + if (launchMode.isDevOrTest()) { instance = readConfig.readStaticField(rootFieldDescriptor); if (!rootName.isEmpty()) { readConfig.invokeVirtualMethod(SB_APPEND_CHAR, readConfigNameBuilder, readConfig.load('.')); @@ -794,7 +782,7 @@ public void run() { clinit.invokeStaticMethod(CD_UNKNOWN_PROPERTIES, clinit.readStaticField(FieldDescriptor.of(cc.getClassName(), "unused", List.class))); - if (devMode) { + if (launchMode.isDevOrTest()) { configSweepLoop(siParserBody, readConfig, runTimeConfig); } // generate sweep for run time @@ -1672,7 +1660,6 @@ public static final class Builder { private LaunchMode launchMode; private ClassOutput classOutput; private BuildTimeConfigurationReader.ReadResult buildTimeReadResult; - private Map runTimeDefaults; private List> additionalTypes; private List additionalBootstrapConfigSourceProviders; @@ -1704,15 +1691,6 @@ public Builder setBuildTimeReadResult(final BuildTimeConfigurationReader.ReadRes return this; } - Map getRunTimeDefaults() { - return runTimeDefaults; - } - - public Builder setRunTimeDefaults(final Map runTimeDefaults) { - this.runTimeDefaults = runTimeDefaults; - return this; - } - List> getAdditionalTypes() { return additionalTypes; } 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 0eacb06801099..287e939985747 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 @@ -35,6 +35,7 @@ import io.quarkus.deployment.builditem.LaunchModeBuildItem; import io.quarkus.deployment.builditem.LiveReloadBuildItem; import io.quarkus.deployment.builditem.RunTimeConfigurationDefaultBuildItem; +import io.quarkus.deployment.builditem.RunTimeConfigurationSourceValueBuildItem; import io.quarkus.deployment.builditem.StaticInitConfigSourceFactoryBuildItem; import io.quarkus.deployment.builditem.StaticInitConfigSourceProviderBuildItem; import io.quarkus.deployment.builditem.SuppressNonRuntimeConfigChangedWarningBuildItem; @@ -48,7 +49,7 @@ import io.quarkus.gizmo.ClassOutput; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.StaticInitSafe; -import io.quarkus.runtime.configuration.ConfigChangeRecorder; +import io.quarkus.runtime.configuration.ConfigRecorder; import io.quarkus.runtime.configuration.ConfigurationRuntimeConfig; import io.quarkus.runtime.configuration.RuntimeOverrideConfigSource; import io.smallrye.config.ConfigSourceFactory; @@ -74,13 +75,24 @@ void staticInitSources( PropertiesLocationConfigSourceFactory.class.getName())); } + @BuildStep + @Record(ExecutionTime.RUNTIME_INIT) + RunTimeConfigurationSourceValueBuildItem devTestConfig(List runTimeDefaults, + ConfigRecorder recorder) { + if (runTimeDefaults.isEmpty()) { + return null; + } + return new RunTimeConfigurationSourceValueBuildItem(recorder.config(runTimeDefaults.stream().collect( + Collectors.toMap(RunTimeConfigurationDefaultBuildItem::getKey, RunTimeConfigurationDefaultBuildItem::getValue)), + Integer.MIN_VALUE + 50)); + } + /** * Generate the Config class that instantiates MP Config and holds all the config objects */ @BuildStep void generateConfigClass( ConfigurationBuildItem configItem, - List runTimeDefaults, List typeItems, LaunchModeBuildItem launchModeBuildItem, BuildProducer generatedClass, @@ -95,13 +107,6 @@ void generateConfigClass( return; } - 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"); - } - } - Set discoveredConfigSources = discoverService(ConfigSource.class, reflectiveClass); Set discoveredConfigSourceProviders = discoverService(ConfigSourceProvider.class, reflectiveClass); Set discoveredConfigSourceFactories = discoverService(ConfigSourceFactory.class, reflectiveClass); @@ -120,7 +125,6 @@ void generateConfigClass( .setBuildTimeReadResult(configItem.getReadResult()) .setClassOutput(new GeneratedClassGizmoAdaptor(generatedClass, false)) .setLaunchMode(launchModeBuildItem.getLaunchMode()) - .setRunTimeDefaults(defaults) .setAdditionalTypes(typeItems.stream().map(ConfigurationTypeBuildItem::getValueType).collect(toList())) .setAdditionalBootstrapConfigSourceProviders( getAdditionalBootstrapConfigSourceProviders(additionalBootstrapConfigSourceProviders)) @@ -157,7 +161,7 @@ public SuppressNonRuntimeConfigChangedWarningBuildItem ignoreQuarkusProfileChang @BuildStep @Record(ExecutionTime.RUNTIME_INIT) public void checkForBuildTimeConfigChange( - ConfigChangeRecorder recorder, ConfigurationBuildItem configItem, LoggingSetupBuildItem loggingSetupBuildItem, + ConfigRecorder recorder, ConfigurationBuildItem configItem, LoggingSetupBuildItem loggingSetupBuildItem, ConfigurationRuntimeConfig configurationConfig, List suppressNonRuntimeConfigChangedWarningItems) { BuildTimeConfigurationReader.ReadResult readResult = configItem.getReadResult(); diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigChangeRecorder.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigRecorder.java similarity index 72% rename from core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigChangeRecorder.java rename to core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigRecorder.java index eb7a8e09bb58f..0ac68312921fc 100644 --- a/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigChangeRecorder.java +++ b/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigRecorder.java @@ -1,6 +1,7 @@ package io.quarkus.runtime.configuration; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; @@ -8,15 +9,19 @@ 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 org.jboss.logging.Logger; +import io.quarkus.runtime.RuntimeValue; import io.quarkus.runtime.annotations.Recorder; import io.quarkus.runtime.configuration.ConfigurationRuntimeConfig.BuildTimeMismatchAtRuntime; +import io.smallrye.config.common.MapBackedConfigSource; @Recorder -public class ConfigChangeRecorder { +public class ConfigRecorder { - private static final Logger log = Logger.getLogger(ConfigChangeRecorder.class); + private static final Logger log = Logger.getLogger(ConfigRecorder.class); public void handleConfigChange(ConfigurationRuntimeConfig configurationConfig, Map buildTimeConfig) { Config configProvider = ConfigProvider.getConfig(); @@ -50,4 +55,14 @@ public void handleConfigChange(ConfigurationRuntimeConfig configurationConfig, M } } + + public RuntimeValue config(Map values, int priority) { + return new RuntimeValue<>(new ConfigSourceProvider() { + @Override + public Iterable getConfigSources(ClassLoader forClassLoader) { + return Collections.singleton(new MapBackedConfigSource("Runtime Default Values", values, priority) { + }); + } + }); + } }