1515 */
1616package io .smallrye .config ;
1717
18- import static io .smallrye .config .ConfigSourceInterceptor .EMPTY ;
19- import static io .smallrye .config .common .utils .StringUtil .replaceNonAlphanumericByUnderscores ;
20- import static io .smallrye .config .common .utils .StringUtil .toLowerCaseAndDotted ;
18+ import io .smallrye .common .annotation .Experimental ;
19+ import io .smallrye .config .SmallRyeConfigBuilder .InterceptorWithPriority ;
20+ import org .eclipse .microprofile .config .Config ;
21+ import org .eclipse .microprofile .config .ConfigProvider ;
22+ import org .eclipse .microprofile .config .spi .ConfigSource ;
23+ import org .eclipse .microprofile .config .spi .ConfigSourceProvider ;
24+ import org .eclipse .microprofile .config .spi .Converter ;
2125
2226import java .io .ObjectStreamException ;
2327import java .io .Serializable ;
3943import java .util .concurrent .ConcurrentHashMap ;
4044import java .util .function .IntFunction ;
4145
42- import org .eclipse .microprofile .config .Config ;
43- import org .eclipse .microprofile .config .ConfigProvider ;
44- import org .eclipse .microprofile .config .spi .ConfigSource ;
45- import org .eclipse .microprofile .config .spi .ConfigSourceProvider ;
46- import org .eclipse .microprofile .config .spi .Converter ;
47-
48- import io .smallrye .common .annotation .Experimental ;
49- import io .smallrye .config .SmallRyeConfigBuilder .InterceptorWithPriority ;
46+ import static io .smallrye .config .ConfigSourceInterceptor .EMPTY ;
47+ import static io .smallrye .config .common .utils .StringUtil .replaceNonAlphanumericByUnderscores ;
48+ import static io .smallrye .config .common .utils .StringUtil .toLowerCaseAndDotted ;
5049
5150/**
5251 * @author <a href="http://jmesnil.net/">Jeff Mesnil</a> (c) 2017 Red Hat inc.
@@ -112,7 +111,7 @@ public <T, C extends Collection<T>> C getValues(String name, Converter<T> conver
112111 }
113112
114113 public <T , C extends Collection <T >> C getIndexedValues (String name , Converter <T > converter ,
115- IntFunction <C > collectionFactory ) {
114+ IntFunction <C > collectionFactory ) {
116115 List <String > indexedProperties = getIndexedProperties (name );
117116 if (indexedProperties .isEmpty ()) {
118117 throw new NoSuchElementException (ConfigMessages .msg .propertyNotFound (name ));
@@ -142,7 +141,7 @@ public List<Integer> getIndexedPropertiesIndexes(final String property) {
142141 if (propertyName .startsWith (property ) && propertyName .length () > property .length ()) {
143142 int index = property .length ();
144143 if (propertyName .charAt (index ) == '[' ) {
145- for (;; ) {
144+ for (; ; ) {
146145 if (propertyName .charAt (index ) == ']' ) {
147146 try {
148147 indexes .add (Integer .parseInt (propertyName .substring (property .length () + 1 , index )));
@@ -172,14 +171,14 @@ public <T> T getValue(String name, Class<T> aClass) {
172171 /**
173172 * Return the content of the direct sub properties as the requested type of Map.
174173 *
175- * @param name The configuration property name
174+ * @param name The configuration property name
176175 * @param kClass the type into which the keys should be converted
177176 * @param vClass the type into which the values should be converted
178- * @param <K> the key type
179- * @param <V> the value type
177+ * @param <K> the key type
178+ * @param <V> the value type
180179 * @return the resolved property value as an instance of the requested Map (not {@code null})
181180 * @throws IllegalArgumentException if a key or a value cannot be converted to the specified types
182- * @throws NoSuchElementException if no direct sub properties could be found.
181+ * @throws NoSuchElementException if no direct sub properties could be found.
183182 */
184183 public <K , V > Map <K , V > getValues (String name , Class <K > kClass , Class <V > vClass ) {
185184 final Map <K , V > result = getValuesAsMap (name , requireConverter (kClass ), requireConverter (vClass ));
@@ -192,11 +191,11 @@ public <K, V> Map<K, V> getValues(String name, Class<K> kClass, Class<V> vClass)
192191 /**
193192 * Return the content of the direct sub properties as the requested type of Map.
194193 *
195- * @param name The configuration property name
196- * @param keyConverter The converter to use for the keys.
194+ * @param name The configuration property name
195+ * @param keyConverter The converter to use for the keys.
197196 * @param valueConverter The converter to use for the values.
198- * @param <K> The type of the keys.
199- * @param <V> The type of the values.
197+ * @param <K> The type of the keys.
198+ * @param <V> The type of the values.
200199 * @return the resolved property value as an instance of the requested Map or {@code null} if it could not be found.
201200 * @throws IllegalArgumentException if a key or a value cannot be converted to the specified types
202201 */
@@ -223,7 +222,6 @@ public <K, V> Map<K, V> getValuesAsMap(String name, Converter<K> keyConverter, C
223222 }
224223
225224 /**
226- *
227225 * This method handles calls from both {@link Config#getValue} and {@link Config#getOptionalValue}.<br>
228226 */
229227 @ SuppressWarnings ("unchecked" )
@@ -246,17 +244,17 @@ public <T> T getValue(String name, Converter<T> converter) {
246244 /**
247245 * This method handles converting values for both CDI injections and programatical calls.<br>
248246 * <br>
249- *
247+ * <p>
250248 * Calls for converting non-optional values ({@link Config#getValue} and "Injecting Native Values")
251249 * should throw an {@link Exception} for each of the following:<br>
252- *
250+ * <p>
253251 * 1. {@link IllegalArgumentException} - if the property cannot be converted by the {@link Converter} to the specified type
254252 * <br>
255253 * 2. {@link NoSuchElementException} - if the property is not defined <br>
256254 * 3. {@link NoSuchElementException} - if the property is defined as an empty string <br>
257255 * 4. {@link NoSuchElementException} - if the {@link Converter} returns {@code null} <br>
258256 * <br>
259- *
257+ * <p>
260258 * Calls for converting optional values ({@link Config#getOptionalValue} and "Injecting Optional Values")
261259 * should only throw an {@link Exception} for #1 ({@link IllegalArgumentException} when the property cannot be converted to
262260 * the specified type).
@@ -312,7 +310,7 @@ public <T> T convertValue(ConfigValue configValue, Converter<T> converter) {
312310 * Determine whether the <em>raw value</em> of a configuration property is exactly equal to the expected given
313311 * value.
314312 *
315- * @param name the property name (must not be {@code null})
313+ * @param name the property name (must not be {@code null})
316314 * @param expected the expected value (may be {@code null})
317315 * @return {@code true} if the values are equal, {@code false} otherwise
318316 */
@@ -344,11 +342,11 @@ public <T> Optional<T> getOptionalValue(String name, Class<T> aClass) {
344342 /**
345343 * Return the content of the direct sub properties as the requested type of Map.
346344 *
347- * @param name The configuration property name
345+ * @param name The configuration property name
348346 * @param kClass the type into which the keys should be converted
349347 * @param vClass the type into which the values should be converted
350- * @param <K> the key type
351- * @param <V> the value type
348+ * @param <K> the key type
349+ * @param <V> the value type
352350 * @return the resolved property value as an instance of the requested Map (not {@code null})
353351 * @throws IllegalArgumentException if a key or a value cannot be converted to the specified types
354352 */
@@ -365,12 +363,12 @@ public <T> Optional<List<T>> getOptionalValues(final String propertyName, final
365363 }
366364
367365 public <T , C extends Collection <T >> Optional <C > getOptionalValues (String name , Class <T > itemClass ,
368- IntFunction <C > collectionFactory ) {
366+ IntFunction <C > collectionFactory ) {
369367 return getOptionalValues (name , requireConverter (itemClass ), collectionFactory );
370368 }
371369
372370 public <T , C extends Collection <T >> Optional <C > getOptionalValues (String name , Converter <T > converter ,
373- IntFunction <C > collectionFactory ) {
371+ IntFunction <C > collectionFactory ) {
374372 final Optional <C > optionalValue = getOptionalValue (name ,
375373 Converters .newCollectionConverter (converter , collectionFactory ));
376374 if (optionalValue .isPresent ()) {
@@ -381,7 +379,7 @@ public <T, C extends Collection<T>> Optional<C> getOptionalValues(String name, C
381379 }
382380
383381 public <T , C extends Collection <T >> Optional <C > getIndexedOptionalValues (String name , Converter <T > converter ,
384- IntFunction <C > collectionFactory ) {
382+ IntFunction <C > collectionFactory ) {
385383 List <String > indexedProperties = getIndexedProperties (name );
386384 if (indexedProperties .isEmpty ()) {
387385 return Optional .empty ();
@@ -459,11 +457,42 @@ public Optional<ConfigSource> getConfigSource(final String name) {
459457 return Optional .empty ();
460458 }
461459
460+ /**
461+ * Return a {@link Config} containing every key from the current {@link Config} that starts with the specified
462+ * prefix. The prefix is removed from the keys in the subset. For example, if the configuration contains the following
463+ * properties:
464+ *
465+ * <pre>
466+ * prefix.number = 1
467+ * prefix.string = Hello
468+ * prefixed.foo = bar
469+ * prefix = World
470+ * </pre>
471+ * <p>
472+ * the Configuration returned by {@code subset("prefix")} will contain the properties:
473+ *
474+ * <pre>
475+ * number = 1
476+ * string = Hello
477+ * = World
478+ * </pre>
479+ * <p>
480+ * (The key for the value "World" is an empty string)
481+ * <p>
482+ *
483+ * @param prefix The prefix used to select the properties.
484+ * @return a subset configuration
485+ */
486+ @ Experimental ("Return a subset of the configuration" )
487+ public Config subset (final String prefix ) {
488+ return new SmallRyeSubsetConfig (prefix , this );
489+ }
490+
462491 public <T > T convert (String value , Class <T > asType ) {
463492 return value != null ? requireConverter (asType ).convert (value ) : null ;
464493 }
465494
466- @ SuppressWarnings ({ "unchecked" , "rawtypes" })
495+ @ SuppressWarnings ({"unchecked" , "rawtypes" })
467496 private <T > Converter <Optional <T >> getOptionalConverter (Class <T > asType ) {
468497 return optionalConverters .computeIfAbsent (asType ,
469498 clazz -> Converters .newOptionalConverter (requireConverter ((Class ) clazz )));
@@ -733,7 +762,7 @@ private static List<ConfigurableConfigSource> getConfigurableSources(final List<
733762 * If <code>FOO_BAR</code> is present a property <code>foo.bar</code> is required.
734763 */
735764 private static Set <String > generateDottedProperties (final List <ConfigSource > sources ,
736- final SmallRyeConfigSourceInterceptorContext current ) {
765+ final SmallRyeConfigSourceInterceptorContext current ) {
737766 // Collect all known properties
738767 Set <String > properties = new HashSet <>();
739768 Iterator <String > iterateNames = current .iterateNames ();
0 commit comments