From 71a57e580df30ed13b90e2724566a71a6e6cc6cb Mon Sep 17 00:00:00 2001 From: George Gastaldi Date: Thu, 24 Aug 2023 13:15:38 -0300 Subject: [PATCH] Introduce SmallRyeConfig.subset - Fixes #981 --- .../io/smallrye/config/SmallRyeConfig.java | 12 ++- .../smallrye/config/SmallRyeSubsetConfig.java | 85 +++++++++++++++++++ .../smallrye/config/SmallRyeConfigTest.java | 44 ++++++---- 3 files changed, 119 insertions(+), 22 deletions(-) create mode 100644 implementation/src/main/java/io/smallrye/config/SmallRyeSubsetConfig.java diff --git a/implementation/src/main/java/io/smallrye/config/SmallRyeConfig.java b/implementation/src/main/java/io/smallrye/config/SmallRyeConfig.java index c4c3c98ed..2a45b9833 100644 --- a/implementation/src/main/java/io/smallrye/config/SmallRyeConfig.java +++ b/implementation/src/main/java/io/smallrye/config/SmallRyeConfig.java @@ -223,7 +223,6 @@ public Map getValuesAsMap(String name, Converter keyConverter, C } /** - * * This method handles calls from both {@link Config#getValue} and {@link Config#getOptionalValue}.
*/ @SuppressWarnings("unchecked") @@ -246,17 +245,17 @@ public T getValue(String name, Converter converter) { /** * This method handles converting values for both CDI injections and programatical calls.
*
- * + *

* Calls for converting non-optional values ({@link Config#getValue} and "Injecting Native Values") * should throw an {@link Exception} for each of the following:
- * + *

* 1. {@link IllegalArgumentException} - if the property cannot be converted by the {@link Converter} to the specified type *
* 2. {@link NoSuchElementException} - if the property is not defined
* 3. {@link NoSuchElementException} - if the property is defined as an empty string
* 4. {@link NoSuchElementException} - if the {@link Converter} returns {@code null}
*
- * + *

* Calls for converting optional values ({@link Config#getOptionalValue} and "Injecting Optional Values") * should only throw an {@link Exception} for #1 ({@link IllegalArgumentException} when the property cannot be converted to * the specified type). @@ -459,6 +458,11 @@ public Optional getConfigSource(final String name) { return Optional.empty(); } + @Experimental("Return a subset of the configuration") + public Config subset(final String prefix) { + return new SmallRyeSubsetConfig(prefix, this); + } + public T convert(String value, Class asType) { return value != null ? requireConverter(asType).convert(value) : null; } diff --git a/implementation/src/main/java/io/smallrye/config/SmallRyeSubsetConfig.java b/implementation/src/main/java/io/smallrye/config/SmallRyeSubsetConfig.java new file mode 100644 index 000000000..6e4163b06 --- /dev/null +++ b/implementation/src/main/java/io/smallrye/config/SmallRyeSubsetConfig.java @@ -0,0 +1,85 @@ +package io.smallrye.config; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +import org.eclipse.microprofile.config.Config; +import org.eclipse.microprofile.config.ConfigValue; +import org.eclipse.microprofile.config.spi.ConfigSource; +import org.eclipse.microprofile.config.spi.Converter; + +/** + * @author George Gastaldi + */ +public class SmallRyeSubsetConfig implements Config { + + private final String prefix; + + private final Config delegate; + + public SmallRyeSubsetConfig(String prefix, Config delegate) { + this.prefix = prefix; + this.delegate = delegate; + } + + @Override + public T getValue(String propertyName, Class propertyType) { + return delegate.getValue(toSubsetPropertyName(propertyName), propertyType); + } + + @Override + public ConfigValue getConfigValue(String propertyName) { + return delegate.getConfigValue(toSubsetPropertyName(propertyName)); + } + + @Override + public List getValues(String propertyName, Class propertyType) { + return delegate.getValues(toSubsetPropertyName(propertyName), propertyType); + } + + @Override + public Optional getOptionalValue(String propertyName, Class propertyType) { + return delegate.getOptionalValue(toSubsetPropertyName(propertyName), propertyType); + } + + @Override + public Optional> getOptionalValues(String propertyName, Class propertyType) { + return delegate.getOptionalValues(toSubsetPropertyName(propertyName), propertyType); + } + + @Override + public Iterable getPropertyNames() { + return StreamSupport.stream(delegate.getPropertyNames().spliterator(), false) + .filter(propertyName -> propertyName.startsWith(prefix)) + .map(this::chopSubsetPropertyName) + .collect(Collectors.toSet()); + } + + @Override + public Iterable getConfigSources() { + return delegate.getConfigSources(); + } + + @Override + public Optional> getConverter(Class forType) { + return delegate.getConverter(forType); + } + + @Override + public T unwrap(Class type) { + return delegate.unwrap(type); + } + + private String toSubsetPropertyName(String propertyName) { + if (propertyName.isBlank()) { + return prefix; + } + return prefix + "." + propertyName; + } + + private String chopSubsetPropertyName(String propertyName) { + return propertyName.substring(prefix.length() + 1); + } +} diff --git a/implementation/src/test/java/io/smallrye/config/SmallRyeConfigTest.java b/implementation/src/test/java/io/smallrye/config/SmallRyeConfigTest.java index 9d9f4476d..040a8bd5a 100644 --- a/implementation/src/test/java/io/smallrye/config/SmallRyeConfigTest.java +++ b/implementation/src/test/java/io/smallrye/config/SmallRyeConfigTest.java @@ -1,17 +1,10 @@ package io.smallrye.config; -import static io.smallrye.config.Converters.STRING_CONVERTER; -import static io.smallrye.config.KeyValuesConfigSource.config; -import static java.util.Collections.singletonList; -import static java.util.Collections.singletonMap; -import static java.util.stream.Collectors.toSet; -import static java.util.stream.StreamSupport.stream; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; +import io.smallrye.config.common.AbstractConfigSource; +import io.smallrye.config.common.MapBackedConfigSource; +import org.eclipse.microprofile.config.Config; +import org.eclipse.microprofile.config.spi.ConfigSource; +import org.junit.jupiter.api.Test; import java.util.ArrayList; import java.util.Arrays; @@ -23,12 +16,13 @@ import java.util.Optional; import java.util.Set; -import org.eclipse.microprofile.config.Config; -import org.eclipse.microprofile.config.spi.ConfigSource; -import org.junit.jupiter.api.Test; - -import io.smallrye.config.common.AbstractConfigSource; -import io.smallrye.config.common.MapBackedConfigSource; +import static io.smallrye.config.Converters.STRING_CONVERTER; +import static io.smallrye.config.KeyValuesConfigSource.config; +import static java.util.Collections.singletonList; +import static java.util.Collections.singletonMap; +import static java.util.stream.Collectors.toSet; +import static java.util.stream.StreamSupport.stream; +import static org.junit.jupiter.api.Assertions.*; class SmallRyeConfigTest { @Test @@ -405,4 +399,18 @@ void emptyPropertyNames() { assertEquals("value", config.getRawValue("")); } + + @Test + void subset() { + SmallRyeConfig config = new SmallRyeConfigBuilder() + .withSources(config( + "app.foo", "bar", + "app.foo.user", "guest", + "app.foo.password", "apassword")) + .build(); + Config subset = config.subset("app.foo"); + assertEquals("bar", subset.getValue("", String.class)); + assertEquals("guest", subset.getValue("user", String.class)); + assertEquals("apassword", subset.getValue("password", String.class)); + } }