diff --git a/config/config/src/main/java/io/helidon/config/ConfigSourcesRuntime.java b/config/config/src/main/java/io/helidon/config/ConfigSourcesRuntime.java index cb7704e1cb7..103b5dc22f9 100644 --- a/config/config/src/main/java/io/helidon/config/ConfigSourcesRuntime.java +++ b/config/config/src/main/java/io/helidon/config/ConfigSourcesRuntime.java @@ -216,5 +216,10 @@ private ConfigSourceRuntimeBase runtime() { private Optional data() { return data; } + + @Override + public String toString() { + return runtime.toString(); + } } } diff --git a/config/config/src/main/java/io/helidon/config/ObjectNodeImpl.java b/config/config/src/main/java/io/helidon/config/ObjectNodeImpl.java index aa8e39b4b12..4e3b335c8b6 100644 --- a/config/config/src/main/java/io/helidon/config/ObjectNodeImpl.java +++ b/config/config/src/main/java/io/helidon/config/ObjectNodeImpl.java @@ -121,11 +121,7 @@ private MergeableNode mergeWithObjectNode(ObjectNodeImpl node) { ObjectNodeBuilderImpl builder = ObjectNodeBuilderImpl.create(members, resolveTokenFunction); node.forEach((name, member) -> builder.deepMerge(MergingKey.of(name), AbstractNodeBuilderImpl.wrap(member))); - if (node.hasValue()) { - builder.value(node.value); - } else if (hasValue()) { - builder.value(value); - } + node.value().or(this::value).ifPresent(builder::value); return builder.build(); } diff --git a/config/config/src/main/java/io/helidon/config/ValueNodeImpl.java b/config/config/src/main/java/io/helidon/config/ValueNodeImpl.java index 1a64b821b6e..e086c934536 100644 --- a/config/config/src/main/java/io/helidon/config/ValueNodeImpl.java +++ b/config/config/src/main/java/io/helidon/config/ValueNodeImpl.java @@ -76,8 +76,9 @@ static ValueNodeImpl wrap(ValueNode valueNode) { public MergeableNode merge(MergeableNode node) { switch (node.nodeType()) { case OBJECT: + return mergeWithObjectNode((ObjectNodeImpl) node); case LIST: - return node.merge(this); + return mergeWithListNode((ListNodeImpl) node); case VALUE: return node; default: @@ -85,6 +86,28 @@ public MergeableNode merge(MergeableNode node) { } } + private MergeableNode mergeWithListNode(ListNodeImpl node) { + if (node.hasValue()) { + // will not merge, as the new node has priority over this node and we only have a value + return node; + } + + // and this will work fine, as the list node does not have a value, so we just add a value from this node + return node.merge(this); + } + + private MergeableNode mergeWithObjectNode(ObjectNodeImpl node) { + // merge this value node with an object node + ObjectNodeBuilderImpl builder = ObjectNodeBuilderImpl.create(); + + node.forEach((name, member) -> builder + .deepMerge(AbstractNodeBuilderImpl.MergingKey.of(name), AbstractNodeBuilderImpl.wrap(member))); + + node.value().or(this::value).ifPresent(builder::value); + + return builder.build(); + } + @Override public String toString() { return "\"" + value + "\""; diff --git a/config/config/src/test/java/io/helidon/config/Gh1182Override.java b/config/config/src/test/java/io/helidon/config/Gh1182Override.java new file mode 100644 index 00000000000..67e4f20c56e --- /dev/null +++ b/config/config/src/test/java/io/helidon/config/Gh1182Override.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2020 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; + +import java.util.Map; +import java.util.function.Supplier; + +import io.helidon.config.spi.ConfigSource; + +import org.junit.jupiter.api.Test; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +/** + * Unit test to reproduce (and validate fix) of + * Github issue 1182. + */ +public class Gh1182Override { + private static final Map VALUE = Map.of("app1.node1.value", "false"); + private static final Map LIST = Map.of( + "app1.node1.value", "true", + "app1.node1.value.1", "14", + "app1.node1.value.2", "15", + "app1.node1.value.3", "16" + ); + + @Test + void testValue() { + Config config = buildConfig(ConfigSources.create(VALUE)); + + ConfigValue value = config.get("app1.node1.value").asString(); + + assertThat(value, is(ConfigValues.simpleValue("false"))); + } + + @Test + void testList() { + Config config = buildConfig(ConfigSources.create(LIST)); + + ConfigValue value = config.get("app1.node1.value").asString(); + + assertThat(value, is(ConfigValues.simpleValue("true"))); + } + + @Test + void testOverrideValueOverList() { + Config config = buildConfig(ConfigSources.create(VALUE), + ConfigSources.create(LIST)); + + ConfigValue value = config.get("app1.node1.value").asString(); + + assertThat(value, is(ConfigValues.simpleValue("false"))); + } + + @Test + void testOverrideListOverValue() { + Config config = buildConfig(ConfigSources.create(LIST), + ConfigSources.create(VALUE)); + + ConfigValue value = config.get("app1.node1.value").asString(); + + assertThat(value, is(ConfigValues.simpleValue("true"))); + } + + private Config buildConfig(Supplier... sources) { + return Config.builder(sources) + .disableEnvironmentVariablesSource() + .disableSystemPropertiesSource() + .build(); + } +} diff --git a/config/tests/pom.xml b/config/tests/pom.xml index fce3466f866..8e9f97c090a 100644 --- a/config/tests/pom.xml +++ b/config/tests/pom.xml @@ -58,5 +58,6 @@ test-mappers-2-complex test-meta-source test-parsers-1-complex + test-mp-reference diff --git a/config/tests/test-mp-reference/pom.xml b/config/tests/test-mp-reference/pom.xml new file mode 100644 index 00000000000..8e91315428a --- /dev/null +++ b/config/tests/test-mp-reference/pom.xml @@ -0,0 +1,57 @@ + + + + + 4.0.0 + + io.helidon.config.tests + helidon-config-tests-project + 2.0.0-SNAPSHOT + + + helidon-config-test-mp-reference + Helidon Config Tests MP Reference + + + Integration tests of reference in MP + + + + + org.eclipse.microprofile.config + microprofile-config-api + + + io.helidon.config + helidon-config + runtime + + + + org.junit.jupiter + junit-jupiter-api + test + + + org.hamcrest + hamcrest-all + test + + + \ No newline at end of file diff --git a/config/tests/test-mp-reference/src/main/resources/META-INF/microprofile-config.properties b/config/tests/test-mp-reference/src/main/resources/META-INF/microprofile-config.properties new file mode 100644 index 00000000000..6bbb95a236a --- /dev/null +++ b/config/tests/test-mp-reference/src/main/resources/META-INF/microprofile-config.properties @@ -0,0 +1,29 @@ +# +# Copyright (c) 2020 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. +# + +value1=value + +referencing1-1=${value1} +referencing1-2=${value1}-ref +referencing1-3=ref-${value1} +referencing1-4=ref-${value1}-ref + +referencing2-1=${value2} +referencing2-2=${value2}-ref +referencing2-3=ref-${value2} +referencing2-4=ref-${value2}-ref + +referencing3-1=${value1}-${value2} diff --git a/config/tests/test-mp-reference/src/test/java/io/helidon/config/tests/mpref/MpConfigReferenceTest.java b/config/tests/test-mp-reference/src/test/java/io/helidon/config/tests/mpref/MpConfigReferenceTest.java new file mode 100644 index 00000000000..a2cd90172a5 --- /dev/null +++ b/config/tests/test-mp-reference/src/test/java/io/helidon/config/tests/mpref/MpConfigReferenceTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2020 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.mpref; + +import org.eclipse.microprofile.config.Config; +import org.eclipse.microprofile.config.ConfigProvider; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; + +public class MpConfigReferenceTest { + private static final String VALUE_1 = "value"; + private static final String VALUE_2 = "hodnota"; + + private static Config config; + + @BeforeAll + static void initClass() { + System.setProperty("value2", VALUE_2); + + config = ConfigProvider.getConfig(); + } + + @Test + void testValue1() { + test("1", VALUE_1); + } + + @Test + void testValue2() { + test("2", VALUE_2); + } + + @Test + void testBoth() { + test("3", "1", VALUE_1 + "-" + VALUE_2); + } + + private void test(String prefix, String value) { + test(prefix, "1", value); + test(prefix, "2", value + "-ref"); + test(prefix, "3", "ref-" + value); + test(prefix, "4", "ref-" + value + "-ref"); + } + + private void test(String prefix, String suffix, String value) { + String key = "referencing" + prefix + "-" + suffix; + String configured = config.getValue(key, String.class); + + assertThat("Value for key " + key, configured, notNullValue()); + assertThat("Value for key " + key, configured, is(value)); + } +}