diff --git a/config/config-mp/src/main/java/io/helidon/config/mp/MpConfigImpl.java b/config/config-mp/src/main/java/io/helidon/config/mp/MpConfigImpl.java index 8299a1c1cc5..d35fdb91b16 100644 --- a/config/config-mp/src/main/java/io/helidon/config/mp/MpConfigImpl.java +++ b/config/config-mp/src/main/java/io/helidon/config/mp/MpConfigImpl.java @@ -30,6 +30,7 @@ import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.NoSuchElementException; import java.util.Optional; @@ -452,7 +453,11 @@ private Optional> findImplicit(Class type) { if (Enum.class.isAssignableFrom(type)) { return Optional.of(value -> { Class enumClass = (Class) type; - return (T) Enum.valueOf(enumClass, value); + try { + return (T) Enum.valueOf(enumClass, value); + } catch (Exception e) { + return (T) Enum.valueOf(enumClass, value.toUpperCase(Locale.ROOT)); + } }); } // any class that has a "public static T method()" diff --git a/config/config-mp/src/main/java/io/helidon/config/mp/MpConfigProviderResolver.java b/config/config-mp/src/main/java/io/helidon/config/mp/MpConfigProviderResolver.java index 9ecd670227d..4b6f57efdc1 100644 --- a/config/config-mp/src/main/java/io/helidon/config/mp/MpConfigProviderResolver.java +++ b/config/config-mp/src/main/java/io/helidon/config/mp/MpConfigProviderResolver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023 Oracle and/or its affiliates. + * Copyright (c) 2019, 2024 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,6 +32,7 @@ import java.util.stream.Stream; import io.helidon.common.GenericType; +import io.helidon.common.config.GlobalConfig; import io.helidon.config.ConfigValue; import io.helidon.config.MetaConfig; import io.helidon.config.spi.ConfigMapper; @@ -167,8 +168,8 @@ public static void buildTimeEnd() { private ConfigDelegate doRegisterConfig(Config config, ClassLoader classLoader) { ConfigDelegate currentConfig = CONFIGS.remove(classLoader); - if (config instanceof ConfigDelegate) { - config = ((ConfigDelegate) config).delegate(); + if (config instanceof ConfigDelegate delegate) { + config = delegate.delegate(); } if (null != currentConfig) { @@ -178,6 +179,11 @@ private ConfigDelegate doRegisterConfig(Config config, ClassLoader classLoader) ConfigDelegate newConfig = new ConfigDelegate(config); CONFIGS.put(classLoader, newConfig); + if (classLoader == Thread.currentThread().getContextClassLoader()) { + // this should be the default class loader (we do not support classloader magic in Helidon) + GlobalConfig.config(() -> newConfig, true); + } + return newConfig; } diff --git a/config/config/src/main/java/io/helidon/config/BuilderImpl.java b/config/config/src/main/java/io/helidon/config/BuilderImpl.java index 865b52c4d88..a1bd6f09681 100644 --- a/config/config/src/main/java/io/helidon/config/BuilderImpl.java +++ b/config/config/src/main/java/io/helidon/config/BuilderImpl.java @@ -61,6 +61,7 @@ class BuilderImpl implements Config.Builder { private MergingStrategy mergingStrategy = MergingStrategy.fallback(); private boolean hasSystemPropertiesSource; private boolean hasEnvVarSource; + private boolean sourcesConfigured; /* * Config mapper providers */ @@ -123,6 +124,8 @@ public Config.Builder sources(List> sourceSuppl sourceSuppliers.stream() .map(Supplier::get) .forEach(this::addSource); + // this was intentional, even if empty (such as from Config.just()) + this.sourcesConfigured = true; return this; } @@ -427,14 +430,14 @@ private ConfigSourcesRuntime buildConfigSources(ConfigContextImpl context) { envVarAliasGeneratorEnabled = true; } - boolean nothingConfigured = sources.isEmpty(); + boolean nothingConfigured = sources.isEmpty() && !sourcesConfigured; if (nothingConfigured) { // use meta configuration to load all sources - MetaConfig.configSources(mediaType -> context.findParser(mediaType).isPresent(), context.supportedSuffixes()) - .stream() + MetaConfigFinder.findConfigSource(mediaType -> context.findParser(mediaType).isPresent(), + context.supportedSuffixes()) .map(context::sourceRuntimeBase) - .forEach(targetSources::add); + .ifPresent(targetSources::add); } else { // add all configured or discovered sources diff --git a/config/config/src/main/java/io/helidon/config/Config.java b/config/config/src/main/java/io/helidon/config/Config.java index f34c4a88d38..bf59b50f5c3 100644 --- a/config/config/src/main/java/io/helidon/config/Config.java +++ b/config/config/src/main/java/io/helidon/config/Config.java @@ -1635,8 +1635,14 @@ default Builder sources(Supplier configSource, * @see #config(Config) */ default Builder metaConfig() { - MetaConfig.metaConfig() - .ifPresent(this::config); + try { + MetaConfig.metaConfig() + .ifPresent(this::config); + } catch (Exception e) { + System.getLogger(getClass().getName()) + .log(System.Logger.Level.WARNING, "Failed to load SE meta-configuration," + + " please make sure it has correct format.", e); + } return this; } diff --git a/config/config/src/main/java/io/helidon/config/MetaConfig.java b/config/config/src/main/java/io/helidon/config/MetaConfig.java index afbe1b9c502..f78a7df2edb 100644 --- a/config/config/src/main/java/io/helidon/config/MetaConfig.java +++ b/config/config/src/main/java/io/helidon/config/MetaConfig.java @@ -22,7 +22,6 @@ import java.util.Optional; import java.util.ServiceLoader; import java.util.Set; -import java.util.function.Function; import io.helidon.common.HelidonServiceLoader; import io.helidon.common.media.type.MediaType; @@ -241,18 +240,6 @@ static List configSources(Config metaConfig) { return configSources; } - // only interested in config source - static List configSources(Function supportedMediaType, List supportedSuffixes) { - Optional metaConfigOpt = metaConfig(); - - return metaConfigOpt - .map(MetaConfig::configSources) - .orElseGet(() -> MetaConfigFinder.findConfigSource(supportedMediaType, supportedSuffixes) - .map(List::of) - .orElseGet(List::of)); - - } - private static Config createDefault() { // use defaults Config.Builder builder = Config.builder(); diff --git a/config/tests/pom.xml b/config/tests/pom.xml index 28d007e3c1f..870b7571945 100644 --- a/config/tests/pom.xml +++ b/config/tests/pom.xml @@ -64,5 +64,8 @@ config-metadata-meta-api config-metadata-builder-api test-lazy-source + test-no-config-sources + test-default-config-source + test-mp-se-meta diff --git a/config/tests/test-default-config-source/pom.xml b/config/tests/test-default-config-source/pom.xml new file mode 100644 index 00000000000..f5357e2b230 --- /dev/null +++ b/config/tests/test-default-config-source/pom.xml @@ -0,0 +1,63 @@ + + + + + 4.0.0 + + io.helidon.config.tests + helidon-config-tests-project + 4.1.0-SNAPSHOT + ../pom.xml + + helidon-test-default-config-source + Helidon Config Tests Default Config Source + + + Test that when no config sources are configured, we do not fall to meta config, but we want to + use default config sources + + + + + io.helidon.config + helidon-config + + + io.helidon.config + helidon-config-yaml + + + io.helidon.common.testing + helidon-common-testing-junit5 + test + + + org.hamcrest + hamcrest-all + test + + + org.junit.jupiter + junit-jupiter-api + test + + + diff --git a/config/tests/test-default-config-source/src/main/resources/application.yaml b/config/tests/test-default-config-source/src/main/resources/application.yaml new file mode 100644 index 00000000000..cf3e2c3af54 --- /dev/null +++ b/config/tests/test-default-config-source/src/main/resources/application.yaml @@ -0,0 +1,17 @@ +# +# Copyright (c) 2024 Oracle and/or its affiliates. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +value: "from-file" diff --git a/config/tests/test-default-config-source/src/main/resources/meta-config.yaml b/config/tests/test-default-config-source/src/main/resources/meta-config.yaml new file mode 100644 index 00000000000..01468e56507 --- /dev/null +++ b/config/tests/test-default-config-source/src/main/resources/meta-config.yaml @@ -0,0 +1,21 @@ +# +# Copyright (c) 2024 Oracle and/or its affiliates. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# MP style, which would normally fail in Helidon SE, but should be ignored, as we do not specify meta config +add-default-sources: true +sources: + - type: "properties" + classpath: "app.properties" \ No newline at end of file diff --git a/config/tests/test-default-config-source/src/test/java/io/helidon/config/tests/nosources/DefaultSourceTest.java b/config/tests/test-default-config-source/src/test/java/io/helidon/config/tests/nosources/DefaultSourceTest.java new file mode 100644 index 00000000000..6775f4a3211 --- /dev/null +++ b/config/tests/test-default-config-source/src/test/java/io/helidon/config/tests/nosources/DefaultSourceTest.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2024 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.config.tests.nosources; + +import java.util.Optional; + +import io.helidon.config.Config; + +import org.junit.jupiter.api.Test; + +import static io.helidon.common.testing.junit5.OptionalMatcher.optionalValue; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +public class DefaultSourceTest { + @Test + public void testDefaultSource() { + Config config = Config.builder() + .disableSystemPropertiesSource() + .disableEnvironmentVariablesSource() + .build(); + + Optional value = config.get("value") + .asString() + .asOptional(); + + // meta config MUST be ignored + assertThat("We defined not sources, we should fall back to default application.yaml", + value, + optionalValue(is("from-file"))); + } +} diff --git a/config/tests/test-mp-se-meta/pom.xml b/config/tests/test-mp-se-meta/pom.xml new file mode 100644 index 00000000000..54c23faa0b1 --- /dev/null +++ b/config/tests/test-mp-se-meta/pom.xml @@ -0,0 +1,67 @@ + + + + + 4.0.0 + + io.helidon.config.tests + helidon-config-tests-project + 4.1.0-SNAPSHOT + ../pom.xml + + helidon-config-tests-mp-se-meta + Helidon Config Tests MP SE Meta + + + Test that when using MP config with meta-config file name that conflicts with Helidon SE, everything + works as expected. + + + + + io.helidon.config + helidon-config + + + io.helidon.config + helidon-config-mp + + + io.helidon.config + helidon-config-yaml + + + io.helidon.common.testing + helidon-common-testing-junit5 + test + + + org.hamcrest + hamcrest-all + test + + + org.junit.jupiter + junit-jupiter-api + test + + + diff --git a/config/tests/test-mp-se-meta/src/main/resources/app.properties b/config/tests/test-mp-se-meta/src/main/resources/app.properties new file mode 100644 index 00000000000..763fa6bd7c6 --- /dev/null +++ b/config/tests/test-mp-se-meta/src/main/resources/app.properties @@ -0,0 +1,17 @@ +# +# Copyright (c) 2024 Oracle and/or its affiliates. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +helidon.test.value=value diff --git a/config/tests/test-mp-se-meta/src/main/resources/application.yaml b/config/tests/test-mp-se-meta/src/main/resources/application.yaml new file mode 100644 index 00000000000..496e0c1ed88 --- /dev/null +++ b/config/tests/test-mp-se-meta/src/main/resources/application.yaml @@ -0,0 +1,17 @@ +# +# Copyright (c) 2024 Oracle and/or its affiliates. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +helidon.app.value: "app-value" \ No newline at end of file diff --git a/config/tests/test-mp-se-meta/src/main/resources/meta-config.yaml b/config/tests/test-mp-se-meta/src/main/resources/meta-config.yaml new file mode 100644 index 00000000000..607b6f02e6d --- /dev/null +++ b/config/tests/test-mp-se-meta/src/main/resources/meta-config.yaml @@ -0,0 +1,22 @@ +# +# Copyright (c) 2024 Oracle and/or its affiliates. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# This is an MP meta-config. It should not be named like this, but if the user does it, we should +# honor it +add-default-sources: true +sources: + - type: "properties" + classpath: "app.properties" \ No newline at end of file diff --git a/config/tests/test-mp-se-meta/src/test/java/io/helidon/config/tests/mpsemeta/MpSeMetaTest.java b/config/tests/test-mp-se-meta/src/test/java/io/helidon/config/tests/mpsemeta/MpSeMetaTest.java new file mode 100644 index 00000000000..46ef7958ee4 --- /dev/null +++ b/config/tests/test-mp-se-meta/src/test/java/io/helidon/config/tests/mpsemeta/MpSeMetaTest.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2024 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.config.tests.mpsemeta; + +import io.helidon.common.config.GlobalConfig; + +import org.eclipse.microprofile.config.Config; +import org.eclipse.microprofile.config.ConfigProvider; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; + +import static io.helidon.common.testing.junit5.OptionalMatcher.optionalValue; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class MpSeMetaTest { + @Order(0) + @Test + public void testSeMeta() { + // this should not fail + io.helidon.config.Config config = io.helidon.config.Config.create(); + assertThat(config.get("helidon.app.value").asString().asOptional(), + optionalValue(is("app-value"))); + } + + @Order(1) + @Test + public void testMpMeta() { + System.setProperty("io.helidon.config.mp.meta-config", "meta-config.yaml"); + Config config = ConfigProvider.getConfig(); + assertThat(config.getValue("helidon.test.value", String.class), is("value")); + + assertThat(GlobalConfig.config() + .get("helidon.test.value") + .asString() + .asOptional(), optionalValue(is("value"))); + } +} diff --git a/config/tests/test-no-config-sources/pom.xml b/config/tests/test-no-config-sources/pom.xml new file mode 100644 index 00000000000..e07222e3728 --- /dev/null +++ b/config/tests/test-no-config-sources/pom.xml @@ -0,0 +1,63 @@ + + + + + 4.0.0 + + io.helidon.config.tests + helidon-config-tests-project + 4.1.0-SNAPSHOT + ../pom.xml + + helidon-config-tests-no-config-sources + Helidon Config Tests No Config Sources + + + Test that when no config sources are defined (such as when using Config.just()), we do not + fallback to meta configuration. + + + + + io.helidon.config + helidon-config + + + io.helidon.config + helidon-config-yaml + + + io.helidon.common.testing + helidon-common-testing-junit5 + test + + + org.hamcrest + hamcrest-all + test + + + org.junit.jupiter + junit-jupiter-api + test + + + diff --git a/config/tests/test-no-config-sources/src/main/resources/application.yaml b/config/tests/test-no-config-sources/src/main/resources/application.yaml new file mode 100644 index 00000000000..cf3e2c3af54 --- /dev/null +++ b/config/tests/test-no-config-sources/src/main/resources/application.yaml @@ -0,0 +1,17 @@ +# +# Copyright (c) 2024 Oracle and/or its affiliates. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +value: "from-file" diff --git a/config/tests/test-no-config-sources/src/main/resources/meta-config.yaml b/config/tests/test-no-config-sources/src/main/resources/meta-config.yaml new file mode 100644 index 00000000000..feac5d69543 --- /dev/null +++ b/config/tests/test-no-config-sources/src/main/resources/meta-config.yaml @@ -0,0 +1,20 @@ +# +# Copyright (c) 2024 Oracle and/or its affiliates. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +sources: + - type: "inlined" + properties: + value: "from-meta-config" \ No newline at end of file diff --git a/config/tests/test-no-config-sources/src/test/java/io/helidon/config/tests/nosources/NoSourcesTest.java b/config/tests/test-no-config-sources/src/test/java/io/helidon/config/tests/nosources/NoSourcesTest.java new file mode 100644 index 00000000000..f0bf1ff212e --- /dev/null +++ b/config/tests/test-no-config-sources/src/test/java/io/helidon/config/tests/nosources/NoSourcesTest.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2024 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.config.tests.nosources; + +import java.util.List; +import java.util.Optional; + +import io.helidon.config.Config; + +import org.junit.jupiter.api.Test; + +import static io.helidon.common.testing.junit5.OptionalMatcher.optionalEmpty; +import static io.helidon.common.testing.junit5.OptionalMatcher.optionalValue; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +public class NoSourcesTest { + @Test + public void testJust() { + Config config = Config.just(); + + Optional value = config.get("value") + .asString() + .asOptional(); + + assertThat("We have used Config.just(), there should be NO config source", value, is(optionalEmpty())); + } + + @Test + public void testBuilder() { + Config config = Config.builder() + .disableEnvironmentVariablesSource() + .disableSystemPropertiesSource() + .sources(List.of()) + .build(); + + Optional value = config.get("value") + .asString() + .asOptional(); + + assertThat("We have used Config.builder() without specifying any source, there should be NO config source", + value, + is(optionalEmpty())); + } + + @Test + public void testMetaConfigExplicit() { + // a sanity check that meta configuration works when requested + + Config config = Config.builder() + .disableEnvironmentVariablesSource() + .disableSystemPropertiesSource() + .metaConfig() + .build(); + + Optional value = config.get("value") + .asString() + .asOptional(); + + assertThat("We have used metaConfig(), there should be the inlined config source configured", + value, + optionalValue(is("from-meta-config"))); + } + + @Test + public void testMetaConfigCreate() { + // a sanity check that meta configuration works when requested + + Config config = Config.create(); + + Optional value = config.get("value") + .asString() + .asOptional(); + + assertThat("We have used Config.create(), there should be the inlined config source configured", + value, + optionalValue(is("from-meta-config"))); + } +} diff --git a/docs/src/main/asciidoc/mp/config/advanced-configuration.adoc b/docs/src/main/asciidoc/mp/config/advanced-configuration.adoc index 16d3b1e85cf..af3239ac18d 100644 --- a/docs/src/main/asciidoc/mp/config/advanced-configuration.adoc +++ b/docs/src/main/asciidoc/mp/config/advanced-configuration.adoc @@ -119,7 +119,9 @@ If a file named `mp-meta-config.yaml`, or `mp-meta-config.properties` is in the on the classpath, and there is no explicit setup of configuration in the code, the configuration will be loaded from the `meta-config` file. The location of the file can be overridden using system property `io.helidon.config.mp.meta-config`, -or environment variable `HELIDON_MP_META_CONFIG` +or environment variable `HELIDON_MP_META_CONFIG`. + +*Important Note:* Do not use custom files named `meta-config.*`, as even when using Micro-Profile, we still use Helidon configuration in some of our components, and this file would be recognized as a Helidon SE Meta Configuration file, which may cause erroneous behavior. [source,yaml] .Example of a YAML meta configuration file: