6 | * A secret configuration value may be expressed as {@code ${handler::value}}, where the {@code handler} is
7 | * the name of the {@code SecretKeysHandler} to use for decode or decryption the {@code value} separated by a
8 | * double colon {@code ::}.
9 | *
10 | * Instances of this interface will be discovered via the {@link java.util.ServiceLoader} mechanism and can be
11 | * registered by providing a {@code META-INF/services/io.smallrye.config.SecretKeysHandler} which contains the fully
12 | * qualified class name of the custom {@code SecretKeysHandler} implementation.
13 | *
14 | * @see io.smallrye.config.SecretKeysHandlerFactory
15 | */
16 | public interface SecretKeysHandler {
17 | /**
18 | * Decodes the secret configuration value.
19 | *
20 | * @param secret the value to decode.
21 | * @return the secret decoded.
22 | */
23 | String decode(String secret);
24 |
25 | /**
26 | * The name of {@code SecretKeysHandler}.
27 | *
28 | * @return the name of the {@code SecretKeysHandler}.
29 | */
30 | String getName();
31 | }
32 |
--------------------------------------------------------------------------------
/testsuite/extra/src/test/java/io/smallrye/config/test/converter/ConverterBean.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Red Hat, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.smallrye.config.test.converter;
17 |
18 | import jakarta.inject.Inject;
19 |
20 | import org.eclipse.microprofile.config.inject.ConfigProperty;
21 |
22 | public class ConverterBean {
23 |
24 | @Inject
25 | @ConfigProperty(name = "myInt", defaultValue = "1")
26 | private int myInt;
27 |
28 | @Inject
29 | @ConfigProperty(name = "myInteger", defaultValue = "1")
30 | private Integer myInteger;
31 |
32 | public int getInt() {
33 | return myInt;
34 | }
35 |
36 | public Integer getInteger() {
37 | return myInteger;
38 | }
39 | }
--------------------------------------------------------------------------------
/implementation/src/main/java/io/smallrye/config/SmallRyeConfigBuilderCustomizer.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config;
2 |
3 | /**
4 | * This {@code SmallRyeConfigBuilderCustomizer} allows to customize a {@link SmallRyeConfigBuilder}, used to create
5 | * a {@link SmallRyeConfig} instance.
6 | *
7 | * Instances of this interface will be discovered via the {@link java.util.ServiceLoader} mechanism and can be
8 | * registered by providing a {@code META-INF/services/io.smallrye.config.SmallRyeConfigBuilderCustomizer} which
9 | * contains the fully qualified class name of the custom {@link SmallRyeConfigBuilderCustomizer} implementation.
10 | */
11 | public interface SmallRyeConfigBuilderCustomizer {
12 | /**
13 | * Customize the current {@link SmallRyeConfigBuilder}.
14 | *
15 | * @param builder the current {@link SmallRyeConfigBuilder}.
16 | */
17 | void configBuilder(SmallRyeConfigBuilder builder);
18 |
19 | /**
20 | * Returns the customizer priority. Customizers are sorted by ascending priority and executed in that order, meaning
21 | * that higher numeric priorities will be executing last, possible overriding values set by previous customizers.
22 | *
23 | * @return the priority value.
24 | */
25 | default int priority() {
26 | return 0;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/utils/jasypt/src/main/java/io/smallrye/config/jasypt/JasyptSecretKeysHandlerFactory.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config.jasypt;
2 |
3 | import java.util.NoSuchElementException;
4 |
5 | import io.smallrye.config.ConfigSourceContext;
6 | import io.smallrye.config.ConfigValue;
7 | import io.smallrye.config.SecretKeysHandler;
8 | import io.smallrye.config.SecretKeysHandlerFactory;
9 | import io.smallrye.config._private.ConfigMessages;
10 |
11 | public class JasyptSecretKeysHandlerFactory implements SecretKeysHandlerFactory {
12 | @Override
13 | public SecretKeysHandler getSecretKeysHandler(final ConfigSourceContext context) {
14 | String password = requireValue(context, "smallrye.config.secret-handler.jasypt.password");
15 | String algorithm = requireValue(context, "smallrye.config.secret-handler.jasypt.algorithm");
16 | return new JasyptSecretKeysHandler(password, algorithm);
17 | }
18 |
19 | @Override
20 | public String getName() {
21 | return "jasypt";
22 | }
23 |
24 | private static String requireValue(final ConfigSourceContext context, final String name) {
25 | ConfigValue value = context.getValue(name);
26 | if (value != null) {
27 | return value.getValue();
28 | }
29 | throw new NoSuchElementException(ConfigMessages.msg.propertyNotFound(name));
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # ignore .svn metadata files
2 | .svn
3 | # ignore Maven generated target folders
4 | ~
5 | target
6 | # ignore downloaded maven
7 | /tools/maven
8 | /tools/maven.zip
9 | # ignore eclipse files
10 | .project
11 | .classpath
12 | .settings
13 | .metadata
14 | .checkstyle
15 | # ignore m2e annotation processing files
16 | .factorypath
17 | # ignore IDEA files
18 | *.iml
19 | *.ipr
20 | *.iws
21 | .idea
22 | # ignore NetBeans files
23 | nbactions.xml
24 | nb-configuration.xml
25 | catalog.xml
26 | #
27 | maven-ant-tasks.jar
28 | test-output
29 | transaction.log
30 | # vim files
31 | *.swp
32 | /.gitk-tmp.*
33 | atlassian-ide-plugin.xml
34 | # temp files
35 | *~
36 | # maven versions plugin
37 | pom.xml.versionsBackup
38 | # hprof dumps
39 | /*.hprof
40 | # ignore 'randomly' strewn around logs
41 | server.log
42 | # ignore java crashes
43 | hs_err_pid*.log
44 | # H2 databases produced by tests
45 | *.h2.db
46 | # JBoss transaction generated files
47 | PutObjectStoreDirHere
48 | # ignore mvn-rpmbuild repo
49 | /.m2
50 | # ignore eap repo
51 | local-repo-eap
52 |
53 | #These keep hanging around
54 | arquillian/*/server.log*
55 | client/shade/dependency-reduced-pom.xml
56 |
57 | #OS X stuff
58 | .DS_Store
59 |
60 | # Zanata files
61 | **/.zanata-cache/
62 |
63 | # Jenv
64 | .java-version
65 |
66 | # MkDocs
67 | site
68 |
69 | # formatter cache directories
70 | .cache
71 |
--------------------------------------------------------------------------------
/examples/mapping/src/main/java/io/smallrye/config/examples/mapping/DurationConverter.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config.examples.mapping;
2 |
3 | import java.time.Duration;
4 | import java.time.format.DateTimeParseException;
5 | import java.util.regex.Pattern;
6 |
7 | import org.eclipse.microprofile.config.spi.Converter;
8 |
9 | public class DurationConverter implements Converter {
10 | private static final long serialVersionUID = 7499347081928776532L;
11 | private static final String PERIOD_OF_TIME = "PT";
12 | private static final Pattern DIGITS = Pattern.compile("^[-+]?\\d+$");
13 | private static final Pattern START_WITH_DIGITS = Pattern.compile("^[-+]?\\d+.*");
14 |
15 | @Override
16 | public Duration convert(String value) {
17 | value = value.trim();
18 | if (value.isEmpty()) {
19 | return null;
20 | }
21 | if (DIGITS.asPredicate().test(value)) {
22 | return Duration.ofSeconds(Long.parseLong(value));
23 | }
24 |
25 | try {
26 | if (START_WITH_DIGITS.asPredicate().test(value)) {
27 | return Duration.parse(PERIOD_OF_TIME + value);
28 | }
29 |
30 | return Duration.parse(value);
31 | } catch (DateTimeParseException e) {
32 | throw new IllegalArgumentException(e);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/.github/workflows/publish-docs.yml:
--------------------------------------------------------------------------------
1 | name: Publish Docs
2 |
3 | on:
4 | workflow_call:
5 | inputs:
6 | version:
7 | required: true
8 | description: Tag version to perform release
9 | type: string
10 |
11 | permissions:
12 | contents: write
13 |
14 | jobs:
15 | publish-docs:
16 | name: Publish Docs
17 | runs-on: ubuntu-latest
18 |
19 | steps:
20 | - uses: actions/checkout@v6
21 | name: checkout ${{inputs.version}}
22 | with:
23 | ref: ${{inputs.version}}
24 |
25 | - name: git author
26 | run: |
27 | git config --global user.name "SmallRye CI"
28 | git config --global user.email "smallrye@googlegroups.com"
29 |
30 | - uses: actions/setup-python@v6
31 | with:
32 | python-version: '3.9'
33 |
34 | - uses: actions/setup-java@v5
35 | with:
36 | distribution: 'temurin'
37 | java-version: 17
38 |
39 | - name: docs release ${{inputs.version}}
40 | run: |
41 | cd documentation
42 | mvn package
43 | pipx install pipenv
44 | pipenv install
45 | git fetch origin gh-pages --depth=1
46 | pipenv run mike deploy --config-file=mkdocs.yaml --push --update-aliases "${PROJECT_VERSION}" Latest
47 | env:
48 | PROJECT_VERSION: ${{inputs.version}}
49 |
--------------------------------------------------------------------------------
/cdi/src/main/java/io/smallrye/config/inject/MetadataInjectionPoint.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config.inject;
2 |
3 | import java.lang.annotation.Annotation;
4 | import java.lang.reflect.Member;
5 | import java.lang.reflect.Type;
6 | import java.util.Collections;
7 | import java.util.Set;
8 |
9 | import jakarta.enterprise.inject.Default;
10 | import jakarta.enterprise.inject.spi.Annotated;
11 | import jakarta.enterprise.inject.spi.Bean;
12 | import jakarta.enterprise.inject.spi.InjectionPoint;
13 | import jakarta.enterprise.util.AnnotationLiteral;
14 |
15 | class MetadataInjectionPoint implements InjectionPoint {
16 | @Override
17 | public Type getType() {
18 | return InjectionPoint.class;
19 | }
20 |
21 | @SuppressWarnings("serial")
22 | @Override
23 | public Set getQualifiers() {
24 | return Collections.singleton(new AnnotationLiteral() {
25 | });
26 | }
27 |
28 | @Override
29 | public Bean> getBean() {
30 | return null;
31 | }
32 |
33 | @Override
34 | public Member getMember() {
35 | return null;
36 | }
37 |
38 | @Override
39 | public Annotated getAnnotated() {
40 | return null;
41 | }
42 |
43 | @Override
44 | public boolean isDelegate() {
45 | return false;
46 | }
47 |
48 | @Override
49 | public boolean isTransient() {
50 | return false;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/testsuite/extra/src/test/java/io/smallrye/config/test/mapping/KotlinMappingGetter.kt:
--------------------------------------------------------------------------------
1 | package io.smallrye.config.test.mapping
2 |
3 | import io.smallrye.config.ConfigMapping
4 | import io.smallrye.config.SmallRyeConfigBuilder
5 | import io.smallrye.config.WithDefault
6 | import org.junit.jupiter.api.Assertions.assertEquals
7 | import org.junit.jupiter.api.Test
8 |
9 | class KotlinMappingGetter {
10 | @Test
11 | fun mappingGetterNames() {
12 | val config = SmallRyeConfigBuilder()
13 | .withMapping(GraphOption::class.java)
14 | .withDefaultValue("graph.get-tenant", "tenant")
15 | .withDefaultValue("graph.get-client-id", "id")
16 | .withDefaultValue("graph.get-client-secret", "secret")
17 | .withDefaultValue("graph.get-a-boolean", "secret")
18 | .build()
19 |
20 | val mapping = config.getConfigMapping(GraphOption::class.java)
21 | assertEquals("url", mapping.baseUrl)
22 | assertEquals("tenant", mapping.tenant)
23 | assertEquals("id", mapping.clientId)
24 | assertEquals("secret", mapping.clientSecret)
25 | }
26 |
27 | @ConfigMapping(prefix = "graph")
28 | interface GraphOption {
29 | @get:WithDefault("url")
30 | val baseUrl: String
31 | val tenant: String
32 | val clientId: String
33 | val clientSecret: String
34 | val aBoolean: Boolean
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/documentation/src/main/docs/config-sources/hocon.md:
--------------------------------------------------------------------------------
1 | # HOCON Config Source
2 |
3 | This Config Source allows to use the [HOCON](https://github.com/lightbend/config/blob/main/HOCON.md) file format to
4 | load configuration values. The HOCON Config Source loads the
5 | configuration from the file `META-INF/microprofile-config.conf`. It has a lower ordinal (`50`) than the
6 | `microprofile-config.properties`.
7 |
8 | The following dependency is required in the classpath to use the HOCON Config Source:
9 |
10 | ```xml
11 |
12 | io.smallrye.config
13 | smallrye-config-source-hocon
14 | {{attributes['version']}}
15 |
16 | ```
17 |
18 | Expressions defined as `${value}` (unquoted) are resolved internally by the HOCON Config Source as described in the
19 | [HOCON Substitutions](https://github.com/lightbend/config/blob/main/HOCON.md#substitutions) documentation. Quoted
20 | Expressions defined as `"${value}"` are resolved by [SmallRye Config Property Expressions](../config/expressions.md).
21 |
22 | Consider:
23 |
24 | **hocon.conf**
25 | ```conf
26 | {
27 | foo: "bar",
28 | hocon: ${foo},
29 | config: "${foo}"
30 | }
31 | ```
32 |
33 | **application.properties**
34 | ```properties
35 | config_ordinal=1000
36 | foo=baz
37 | ```
38 |
39 | The value of `hocon` is `bar` and the value of `config` is `baz` (if the properties source has a higher ordinal).
40 |
--------------------------------------------------------------------------------
/implementation/src/test/java/io/smallrye/config/InterceptorChainTest.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config;
2 |
3 | import static io.smallrye.config.SmallRyeConfig.SMALLRYE_CONFIG_PROFILE;
4 | import static org.junit.jupiter.api.Assertions.assertEquals;
5 |
6 | import org.eclipse.microprofile.config.Config;
7 | import org.junit.jupiter.api.Test;
8 |
9 | class InterceptorChainTest {
10 | @Test
11 | void chain() {
12 | final Config config = buildConfig(
13 | "my.prop", "1", // original property
14 | "%my.prop.profile", "2", // profile property with expansion
15 | "%prof.my.prop.profile", "3",
16 | "my.prop.relocate", "4", // relocation
17 | "%prof.my.prop.relocate", "${%prof.my.prop.profile}", // profile with relocation
18 | SMALLRYE_CONFIG_PROFILE, "prof" // profile to use
19 | );
20 | assertEquals("3", config.getValue("my.prop", String.class));
21 | }
22 |
23 | private static Config buildConfig(String... keyValues) {
24 | return new SmallRyeConfigBuilder()
25 | .addDefaultSources()
26 | .addDefaultInterceptors()
27 | .withSources(KeyValuesConfigSource.config(keyValues))
28 | .withInterceptors(
29 | new RelocateConfigSourceInterceptor(s -> s.replaceAll("my\\.prop", "my.prop.relocate")))
30 | .build();
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/sources/yaml/src/test/java/io/smallrye/config/source/yaml/YamlConfigSourceLoaderTest.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config.source.yaml;
2 |
3 | import static org.junit.jupiter.api.Assertions.assertEquals;
4 | import static org.junit.jupiter.api.Assertions.assertTrue;
5 |
6 | import java.io.File;
7 | import java.io.FileOutputStream;
8 | import java.net.URL;
9 | import java.net.URLClassLoader;
10 | import java.nio.file.Path;
11 |
12 | import org.junit.jupiter.api.Test;
13 | import org.junit.jupiter.api.io.TempDir;
14 |
15 | import io.smallrye.config.SmallRyeConfig;
16 | import io.smallrye.config.SmallRyeConfigBuilder;
17 |
18 | public class YamlConfigSourceLoaderTest {
19 | @Test
20 | void applicationYaml(@TempDir Path tempDir) throws Exception {
21 | String yaml = "my:\n" +
22 | " prop: 1234\n";
23 | File file = tempDir.resolve("application.yaml").toFile();
24 | try (FileOutputStream out = new FileOutputStream(file)) {
25 | out.write(yaml.getBytes());
26 | }
27 |
28 | SmallRyeConfig config = new SmallRyeConfigBuilder()
29 | .forClassLoader(new URLClassLoader(new URL[] { tempDir.toUri().toURL() }))
30 | .addDiscoveredSources()
31 | .build();
32 |
33 | assertTrue(config.getConfigSources(YamlConfigSource.class).iterator().hasNext());
34 | assertEquals("1234", config.getConfigValue("my.prop").getValue());
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/testsuite/extra/src/test/java/io/smallrye/config/test/source/OrdinalSourceTest.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config.test.source;
2 |
3 | import static org.junit.jupiter.api.Assertions.assertEquals;
4 |
5 | import jakarta.inject.Inject;
6 |
7 | import org.eclipse.microprofile.config.Config;
8 | import org.eclipse.microprofile.config.spi.ConfigSource;
9 | import org.jboss.arquillian.container.test.api.Deployment;
10 | import org.jboss.arquillian.junit5.ArquillianExtension;
11 | import org.jboss.shrinkwrap.api.ShrinkWrap;
12 | import org.jboss.shrinkwrap.api.asset.StringAsset;
13 | import org.jboss.shrinkwrap.api.spec.WebArchive;
14 | import org.junit.jupiter.api.Test;
15 | import org.junit.jupiter.api.extension.ExtendWith;
16 |
17 | @ExtendWith(ArquillianExtension.class)
18 | class OrdinalSourceTest {
19 | @Deployment
20 | static WebArchive deploy() {
21 | return ShrinkWrap.create(WebArchive.class, "ProviderTest.war")
22 | .addAsResource(new StringAsset("config_ordinal=1234"),
23 | "META-INF/microprofile-config.properties")
24 | .as(WebArchive.class);
25 | }
26 |
27 | @Inject
28 | Config config;
29 |
30 | @Test
31 | void ordinal() {
32 | for (ConfigSource configSource : config.getConfigSources()) {
33 | if (configSource.getName().contains("microprofile-config.properties")) {
34 | assertEquals(1234, configSource.getOrdinal());
35 | }
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/examples/configmap/.kubernetes/configmap-app.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: Service
4 | metadata:
5 | name: configmap-app
6 | spec:
7 | type: "LoadBalancer"
8 | ports:
9 | - name: "http"
10 | port: 8080
11 | targetPort: 8080
12 | selector:
13 | app: configmap-app
14 | ---
15 | apiVersion: apps/v1
16 | kind: Deployment
17 | metadata:
18 | name: configmap-app
19 | labels:
20 | app: configmap-app
21 | spec:
22 | replicas: 1
23 | selector:
24 | matchLabels:
25 | app: configmap-app
26 | template:
27 | metadata:
28 | labels:
29 | app: configmap-app
30 | spec:
31 | containers:
32 | - name: configmap-app
33 | image: docker-registry:5000/smallrye-config-examples/configmap-app
34 | imagePullPolicy: Always
35 | ports:
36 | - containerPort: 8080
37 | env:
38 | - name: SMALLRYE_CONFIG_SOURCE_FILE_LOCATION
39 | value: "/usr/local/apps/config"
40 | volumeMounts:
41 | - name: configmap-app
42 | mountPath: /usr/local/apps/config
43 | volumes:
44 | - name: configmap-app
45 | configMap:
46 | name: configmap-app
47 | restartPolicy: Always
48 | ---
49 | apiVersion: v1
50 | kind: ConfigMap
51 | metadata:
52 | name: configmap-app
53 | labels:
54 | app: configmap-app
55 | data:
56 | smallrye.config.example.configmap.foo: something
57 | smallrye.config.example.configmap.bar: something-else
58 |
--------------------------------------------------------------------------------
/testsuite/extra/src/test/java/io/smallrye/config/test/provider/ProviderAlone.java:
--------------------------------------------------------------------------------
1 | /*
2 | * JBoss, Home of Professional Open Source.
3 | * Copyright 2019, Red Hat, Inc., and individual contributors
4 | * as indicated by the @author tags. See the copyright.txt file in the
5 | * distribution for a full listing of individual contributors.
6 | *
7 | * This is free software; you can redistribute it and/or modify it
8 | * under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation; either version 2.1 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * This software is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 | * Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public
18 | * License along with this software; if not, write to the Free
19 | * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 | * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 | */
22 |
23 | package io.smallrye.config.test.provider;
24 |
25 | import jakarta.inject.Inject;
26 | import jakarta.inject.Provider;
27 |
28 | import org.eclipse.microprofile.config.inject.ConfigProperty;
29 |
30 | public class ProviderAlone {
31 |
32 | @Inject
33 | @ConfigProperty(name = "myEmail")
34 | Provider emailProvider;
35 | }
36 |
--------------------------------------------------------------------------------
/implementation/src/main/java/io/smallrye/config/AbstractLocationConfigSourceFactory.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config;
2 |
3 | import static io.smallrye.config.Converters.STRING_CONVERTER;
4 | import static io.smallrye.config.Converters.newArrayConverter;
5 | import static io.smallrye.config.SmallRyeConfig.SMALLRYE_CONFIG_LOCATIONS;
6 |
7 | import java.net.URI;
8 | import java.util.Collections;
9 |
10 | import org.eclipse.microprofile.config.spi.ConfigSource;
11 |
12 | /**
13 | * This {@code AbstractLocationConfigSourceFactory} allows to initialize additional config locations with the
14 | * configuration {@link SmallRyeConfig#SMALLRYE_CONFIG_LOCATIONS}. The configuration support multiple
15 | * locations separated by a comma and each must represent a valid {@link URI}.
16 | */
17 | public abstract class AbstractLocationConfigSourceFactory extends AbstractLocationConfigSourceLoader
18 | implements ConfigSourceFactory {
19 |
20 | @Override
21 | protected boolean failOnMissingFile() {
22 | return true;
23 | }
24 |
25 | @Override
26 | public Iterable getConfigSources(final ConfigSourceContext context) {
27 | final ConfigValue value = context.getValue(SMALLRYE_CONFIG_LOCATIONS);
28 | if (value.getValue() == null) {
29 | return Collections.emptyList();
30 | }
31 |
32 | return loadConfigSources(newArrayConverter(STRING_CONVERTER, String[].class).convert(value.getValue()),
33 | value.getConfigSourceOrdinal());
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/testsuite/extra/src/test/java/io/smallrye/config/test/provider/InstanceAlone.java:
--------------------------------------------------------------------------------
1 | /*
2 | * JBoss, Home of Professional Open Source.
3 | * Copyright 2019, Red Hat, Inc., and individual contributors
4 | * as indicated by the @author tags. See the copyright.txt file in the
5 | * distribution for a full listing of individual contributors.
6 | *
7 | * This is free software; you can redistribute it and/or modify it
8 | * under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation; either version 2.1 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * This software is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 | * Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public
18 | * License along with this software; if not, write to the Free
19 | * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 | * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 | */
22 |
23 | package io.smallrye.config.test.provider;
24 |
25 | import jakarta.enterprise.inject.Instance;
26 | import jakarta.inject.Inject;
27 |
28 | import org.eclipse.microprofile.config.inject.ConfigProperty;
29 |
30 | public class InstanceAlone {
31 |
32 | @Inject
33 | @ConfigProperty(name = "myEmail")
34 | Instance emailInstance;
35 | }
36 |
--------------------------------------------------------------------------------
/utils/events/src/main/java/io/smallrye/config/events/ChangeEvent.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config.events;
2 |
3 | import java.io.Serializable;
4 | import java.util.Optional;
5 |
6 | /**
7 | * an Event on a config element
8 | *
9 | * @author Phillip Kruger
10 | */
11 | public class ChangeEvent implements Serializable {
12 |
13 | private final Type type;
14 | private final String key;
15 | private final Optional oldValue;
16 | private final String newValue;
17 | private final String fromSource;
18 |
19 | public ChangeEvent(Type type, String key, Optional oldValue, String newValue, String fromSource) {
20 | this.type = type;
21 | this.key = key;
22 | this.oldValue = oldValue;
23 | this.newValue = newValue;
24 | this.fromSource = fromSource;
25 | }
26 |
27 | public Type getType() {
28 | return type;
29 | }
30 |
31 | public String getKey() {
32 | return key;
33 | }
34 |
35 | public Optional getOldValue() {
36 | return oldValue;
37 | }
38 |
39 | public String getNewValue() {
40 | return newValue;
41 | }
42 |
43 | public String getFromSource() {
44 | return fromSource;
45 | }
46 |
47 | @Override
48 | public String toString() {
49 | return "ChangeEvent{" + "type=" + type + ", key=" + key + ", oldValue=" + oldValue + ", newValue=" + newValue
50 | + ", fromSource=" + fromSource + '}';
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/implementation/src/test/java/io/smallrye/config/ConfigMappingLoaderParallelTest.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config;
2 |
3 | import static org.junit.jupiter.api.Assertions.assertEquals;
4 |
5 | import org.junit.jupiter.api.Test;
6 | import org.junit.jupiter.api.parallel.Execution;
7 | import org.junit.jupiter.api.parallel.ExecutionMode;
8 |
9 | @Execution(ExecutionMode.CONCURRENT)
10 | class ConfigMappingLoaderParallelTest {
11 | @Test
12 | void testParallelThreadOne() {
13 | loadTestClass();
14 | }
15 |
16 | @Test
17 | void testParallelThreadTwo() {
18 | loadTestClass();
19 | }
20 |
21 | @Test
22 | void testParallelThreadThree() {
23 | loadTestClass();
24 | }
25 |
26 | @Test
27 | void testParallelThreadFour() {
28 | loadTestClass();
29 | }
30 |
31 | private void loadTestClass() {
32 | ConfigMappingLoader.ensureLoaded(ConfigMappingLoaderTest.Server.class);
33 | ConfigMappingLoader.ensureLoaded(ConfigMappingLoaderTest.Server.class);
34 |
35 | SmallRyeConfig config = new SmallRyeConfigBuilder().withSources(
36 | KeyValuesConfigSource.config("server.host", "localhost", "server.port", "8080"))
37 | .withMapping(ConfigMappingLoaderTest.Server.class)
38 | .build();
39 |
40 | ConfigMappingLoaderTest.Server server = config.getConfigMapping(ConfigMappingLoaderTest.Server.class);
41 | assertEquals("localhost", server.host());
42 | assertEquals(8080, server.port());
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/implementation/src/main/java/io/smallrye/config/Secret.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config;
2 |
3 | /**
4 | * A container type to mark a {@link io.smallrye.config.ConfigMapping} member as a {@link Secret} value.
5 | *
6 | *
7 | * A {@link Secret} value modifies the behaviour of the config system by:
8 | *
9 | *
Omitting the name of the secret in {@link SmallRyeConfig#getPropertyNames()}
10 | *
Omitting the name and value of the secret in the mapping {@code toString} method
11 | *
Throwing a {@link SecurityException} when trying to retrieve the value via {@link SmallRyeConfig} programmatic API
12 | *
13 | *
14 | * A {@link ConfigMapping} is still capable of performing the mapping without these restrictions, and the secret value
15 | * is available for retrieval in its declared member:
16 | *
17 | *
25 | *
26 | * A Secret can be of any type that can be converted by a registered
27 | * {@link org.eclipse.microprofile.config.spi.Converter} of the same type.
28 | *
29 | * @param the secret type
30 | *
31 | * @see SecretKeys
32 | * @see SmallRyeConfigBuilder#withSecretKeys(String...)
33 | */
34 | public interface Secret {
35 | /**
36 | * Get the actual value of the {@link Secret}.
37 | *
38 | * @return the actual value of the {@link Secret}.
39 | */
40 | T get();
41 | }
42 |
--------------------------------------------------------------------------------
/implementation/src/main/java/io/smallrye/config/SecretKeysConfigSourceInterceptor.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config;
2 |
3 | import java.io.Serial;
4 | import java.util.Set;
5 |
6 | import jakarta.annotation.Priority;
7 |
8 | import io.smallrye.config._private.ConfigMessages;
9 |
10 | /**
11 | * Intercept the resolution of a configuration name and throw {@link java.lang.SecurityException} if the name is a
12 | * Secret Key and the keys are locked.
13 | *
14 | * To avoid having to recalculate the list of property names, the filter of secret keys is applied in
15 | * {@code SmallRyeConfig.ConfigSources.PropertyNames}, so this interceptor does not implement
16 | * {@link io.smallrye.config.ConfigSourceInterceptor#iterateNames(ConfigSourceInterceptorContext)}.
17 | *
18 | * @see SecretKeys
19 | */
20 | @Priority(Priorities.LIBRARY + 100)
21 | public class SecretKeysConfigSourceInterceptor implements ConfigSourceInterceptor {
22 | @Serial
23 | private static final long serialVersionUID = 7291982039729980590L;
24 |
25 | private final Set secrets;
26 |
27 | public SecretKeysConfigSourceInterceptor(final Set secrets) {
28 | this.secrets = secrets;
29 | }
30 |
31 | @Override
32 | public ConfigValue getValue(final ConfigSourceInterceptorContext context, final String name) {
33 | if (SecretKeys.isLocked() && secrets.contains(PropertyName.unprofiled(name))) {
34 | throw ConfigMessages.msg.notAllowed(name);
35 | }
36 | return context.proceed(name);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/sources/file-system/src/main/java/io/smallrye/config/source/file/FileSystemConfigSourceFactory.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config.source.file;
2 |
3 | import static io.smallrye.config.Converters.newArrayConverter;
4 |
5 | import java.util.Collections;
6 | import java.util.OptionalInt;
7 | import java.util.stream.Collectors;
8 | import java.util.stream.Stream;
9 |
10 | import org.eclipse.microprofile.config.spi.ConfigSource;
11 |
12 | import io.smallrye.config.ConfigSourceContext;
13 | import io.smallrye.config.ConfigSourceFactory;
14 | import io.smallrye.config.ConfigValue;
15 | import io.smallrye.config.Converters;
16 |
17 | public class FileSystemConfigSourceFactory implements ConfigSourceFactory {
18 | public static final String SMALLRYE_CONFIG_SOURCE_FILE_LOCATIONS = "smallrye.config.source.file.locations";
19 |
20 | @Override
21 | public Iterable getConfigSources(final ConfigSourceContext context) {
22 | final ConfigValue value = context.getValue(SMALLRYE_CONFIG_SOURCE_FILE_LOCATIONS);
23 | if (value == null || value.getValue() == null) {
24 | return Collections.emptyList();
25 | }
26 |
27 | return Stream
28 | .of(newArrayConverter(Converters.getImplicitConverter(String.class), String[].class)
29 | .convert(value.getValue()))
30 | .map(location -> new FileSystemConfigSource(location))
31 | .collect(Collectors.toList());
32 | }
33 |
34 | @Override
35 | public OptionalInt getPriority() {
36 | return OptionalInt.of(290);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/sources/file-system/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 | smallrye-config-parent
6 | io.smallrye.config
7 | 3.15.1-SNAPSHOT
8 | ../../pom.xml
9 |
10 |
11 | smallrye-config-source-file-system
12 | SmallRye Config: ConfigSource - FileSystem
13 |
14 |
15 |
16 | io.smallrye.config
17 | smallrye-config-common
18 |
19 |
20 | io.smallrye.config
21 | smallrye-config
22 |
23 |
24 | org.jboss.logging
25 | jboss-logging-annotations
26 |
27 |
28 | org.jboss.logging
29 | jboss-logging-processor
30 |
31 |
32 |
33 | org.junit.jupiter
34 | junit-jupiter
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/documentation/src/main/docs/config/map-support.md:
--------------------------------------------------------------------------------
1 | # Map Support
2 |
3 | SmallRye Config allows injecting multiple configuration parameters as a `Map`. The configuration value syntax is
4 | represented by `property.name.map-key=value` Consider:
5 |
6 | ```properties
7 | server.reasons.200=OK
8 | server.reasons.201=Created
9 | ```
10 |
11 | The previous configuration could be injected directly in a CDI Bean:
12 |
13 | With `@ConfigProperty`
14 |
15 | ```java
16 | @ApplicationScoped
17 | public class ConfigBean {
18 | @Inject
19 | @ConfigProperty(name = "server.reasons")
20 | Map reasons;
21 | }
22 | ```
23 |
24 | With `@ConfigProperties`
25 |
26 | ```java
27 | @ConfigProperties(prefix = "server")
28 | public class Config {
29 | Map reasons;
30 | }
31 | ```
32 |
33 | The `Map` will contains the keys `200` and `201`, which map to the values `OK` and `Created`.
34 |
35 | !!!note
36 |
37 | Only the direct sub properties will be converted into a `Map` and
38 | injected into the target bean, the rest will be ignored. In other words,
39 | in the previous example, a property whose name is `reasons.200.a` would
40 | be ignored as not considered as a direct sub property.
41 |
42 | !!!note
43 |
44 | The property will be considered as missing if no direct sub properties
45 | could be found.
46 |
47 | It is also possible to retrieve the `Map` programmatically by calling the methods
48 | `SmallRyeConfig#getValues("server.reasons", Integer.class, String.class)` or
49 | `SmallRyeConfig#getOptionalValues("server.reasons", Integer.class, String.class)`.
50 |
--------------------------------------------------------------------------------
/implementation/src/main/java/io/smallrye/config/ConfigSourceInterceptorContext.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config;
2 |
3 | import java.io.Serializable;
4 | import java.util.Iterator;
5 |
6 | /**
7 | * Exposes contextual information about the intercepted invocation of {@link ConfigSourceInterceptor}. This allows
8 | * implementers to control the behavior of the invocation chain.
9 | */
10 | public interface ConfigSourceInterceptorContext extends Serializable {
11 | /**
12 | * Proceeds to the next interceptor in the chain.
13 | *
14 | * @param name the configuration name to look up (can be the original key)
15 | * @return a {@link ConfigValue} with information about the name, value, config source and ordinal, or {@code null}
16 | * if the value isn't present.
17 | */
18 | ConfigValue proceed(String name);
19 |
20 | /**
21 | * Re-calls the first interceptor in the chain.
22 | * If the original name is given, then it is possible to cause a recursive loop, so care must be taken.
23 | * This method is intended to be used by relocating and other compatibility-related interceptors.
24 | *
25 | * @param name the configuration name to look up (can be the original key)
26 | * @return a {@link ConfigValue} with information about the name, value, config source and ordinal, or {@code null}
27 | * if the value isn't present.
28 | */
29 | ConfigValue restart(String name);
30 |
31 | /**
32 | * @return an iterator over the configuration names known to this interceptor.
33 | */
34 | Iterator iterateNames();
35 | }
36 |
--------------------------------------------------------------------------------
/sources/hocon/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 | smallrye-config-parent
6 | io.smallrye.config
7 | 3.15.1-SNAPSHOT
8 | ../../pom.xml
9 |
10 |
11 | smallrye-config-source-hocon
12 | SmallRye Config: ConfigSource - HOCON
13 |
14 |
15 | 1.4.5
16 |
17 |
18 |
19 |
20 | com.typesafe
21 | config
22 | ${lightbend-config.version}
23 |
24 |
25 | io.smallrye.config
26 | smallrye-config-core
27 |
28 |
29 |
30 | org.junit.jupiter
31 | junit-jupiter
32 |
33 |
34 | jakarta.annotation
35 | jakarta.annotation-api
36 | test
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/sources/zookeeper/src/main/java/io/smallrye/config/source/zookeeper/ZooKeepperLogging.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config.source.zookeeper;
2 |
3 | import java.lang.invoke.MethodHandles;
4 |
5 | import org.jboss.logging.BasicLogger;
6 | import org.jboss.logging.Logger;
7 | import org.jboss.logging.annotations.Cause;
8 | import org.jboss.logging.annotations.LogMessage;
9 | import org.jboss.logging.annotations.Message;
10 | import org.jboss.logging.annotations.MessageLogger;
11 |
12 | @MessageLogger(projectCode = "SRCFG", length = 5)
13 | interface ZooKeepperLogging extends BasicLogger {
14 | ZooKeepperLogging log = Logger.getMessageLogger(MethodHandles.lookup(), ZooKeepperLogging.class,
15 | ZooKeepperLogging.class.getPackage().getName());
16 |
17 | @LogMessage(level = Logger.Level.WARN)
18 | @Message(id = 4500, value = "Failed to retrieve property names from ZooKeeperConfigSource")
19 | void failedToRetrievePropertyNames(@Cause Throwable throwable);
20 |
21 | @LogMessage(level = Logger.Level.WARN)
22 | @Message(id = 4501, value = "Failed to retrieve properties from ZooKeeperConfigSource")
23 | void failedToRetrieveProperties(@Cause Throwable throwable);
24 |
25 | @LogMessage(level = Logger.Level.WARN)
26 | @Message(id = 4502, value = "Failed to retrieve property value for %s from ZooKeeperConfigSource")
27 | void failedToRetrieveValue(@Cause Throwable throwable, String key);
28 |
29 | @LogMessage(level = Logger.Level.INFO)
30 | @Message(id = 4503, value = "Configuring ZooKeeperConfigSource using url: %s, and applicationId: %s")
31 | void configuringZookeeper(String url, String applicationId);
32 | }
33 |
--------------------------------------------------------------------------------
/implementation/src/test/java/io/smallrye/config/NameIteratorTest.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config;
2 |
3 | import static org.junit.jupiter.api.Assertions.*;
4 |
5 | import org.junit.jupiter.api.Test;
6 |
7 | class NameIteratorTest {
8 | @Test
9 | void getNextSegment() {
10 | NameIterator nameIterator = new NameIterator("foo.bar");
11 | assertEquals("foo", nameIterator.getNextSegment());
12 | assertEquals("foo", nameIterator.getNextSegment());
13 | }
14 |
15 | @Test
16 | void next() {
17 | NameIterator nameIterator = new NameIterator("foo.bar");
18 | nameIterator.next();
19 | assertEquals("bar", nameIterator.getNextSegment());
20 | }
21 |
22 | @Test
23 | void getPreviousSegment() {
24 | NameIterator nameIterator = new NameIterator("foo.bar");
25 | nameIterator.next();
26 | assertEquals("foo", nameIterator.getPreviousSegment());
27 | assertEquals("foo", nameIterator.getPreviousSegment());
28 | }
29 |
30 | @Test
31 | void previous() {
32 | NameIterator nameIterator = new NameIterator("foo.bar");
33 | nameIterator.next();
34 | nameIterator.previous();
35 | assertEquals("foo", nameIterator.getNextSegment());
36 | }
37 |
38 | @Test
39 | void quotes() {
40 | NameIterator nameIterator = new NameIterator("one.\"two.three\".four");
41 | assertEquals("one", nameIterator.getNextSegment());
42 | nameIterator.next();
43 | assertEquals("two.three", nameIterator.getNextSegment());
44 | nameIterator.next();
45 | assertEquals("four", nameIterator.getNextSegment());
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/documentation/src/main/docs/config/indexed-properties.md:
--------------------------------------------------------------------------------
1 | # Indexed Properties
2 |
3 | In [MicroProfile Config](https://github.com/eclipse/microprofile-config/), a config value with unescaped commas may be
4 | converted to `Collection`. It works for simple cases, but it becomes cumbersome and limited for more advanced use cases.
5 |
6 | Indexed Properties provide a way to use indexes in config property names to map specific elements in a `Collection`
7 | type. Since the indexed element is part of the property name, it can also map complex object types. Consider:
8 |
9 | ```properties
10 | # MicroProfile Config - Collection Values
11 | my.collection=dog,cat,turtle
12 |
13 | # SmallRye Config - Indexed Property
14 | my.indexed.collection[0]=dog
15 | my.indexed.collection[1]=cat
16 | my.indexed.collection[2]=turtle
17 | ```
18 |
19 | The indexed property syntax uses the property name and square brackets with an index in between.
20 |
21 | A call to `Config#getValues("my.collection", String.class)`, will automatically create and convert a `List`
22 | that contains the values `dog`, `cat` and `turtle`. A call to `Config#getValues("my.indexed.collection", String.class)`
23 | returns the exact same result. The indexed property format is prioritized when both styles are found in the same
24 | configuration source. When available in multiple sources, the higher ordinal source wins, like any other configuration
25 | lookup.
26 |
27 | The indexed property is sorted by its index before being added to the target `Collection`. Any gaps in the indexes do
28 | not resolve to the target `Collection`, which means that the `Collection` result will store all values without empty
29 | elements.
30 |
--------------------------------------------------------------------------------
/testsuite/extra/src/test/java/io/smallrye/config/test/location/LocationConfigTest.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config.test.location;
2 |
3 | import static org.junit.jupiter.api.Assertions.assertEquals;
4 |
5 | import jakarta.inject.Inject;
6 |
7 | import org.eclipse.microprofile.config.Config;
8 | import org.jboss.arquillian.container.test.api.Deployment;
9 | import org.jboss.arquillian.junit5.ArquillianExtension;
10 | import org.jboss.shrinkwrap.api.ShrinkWrap;
11 | import org.jboss.shrinkwrap.api.asset.StringAsset;
12 | import org.jboss.shrinkwrap.api.spec.WebArchive;
13 | import org.junit.jupiter.api.Test;
14 | import org.junit.jupiter.api.extension.ExtendWith;
15 |
16 | @ExtendWith(ArquillianExtension.class)
17 | public class LocationConfigTest {
18 | @Deployment
19 | static WebArchive deploy() {
20 | return ShrinkWrap.create(WebArchive.class, "LocationConfigTest.war")
21 | .addAsResource(new StringAsset("smallrye.config.locations=config.properties,config.yml"),
22 | "META-INF/microprofile-config.properties")
23 | .addAsResource(new StringAsset("my.prop=1234"), "config.properties")
24 | .addAsResource(new StringAsset("my:\n" +
25 | " yml: 1234\n"), "config.yml")
26 | .as(WebArchive.class);
27 | }
28 |
29 | @Inject
30 | Config config;
31 |
32 | @Test
33 | void locationConfig() {
34 | assertEquals("config.properties,config.yml", config.getValue("smallrye.config.locations", String.class));
35 | assertEquals("1234", config.getValue("my.prop", String.class));
36 | assertEquals("1234", config.getValue("my.yml", String.class));
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/testsuite/extra/src/test/java/io/smallrye/config/test/provider/ProviderBean.java:
--------------------------------------------------------------------------------
1 | /*
2 | * JBoss, Home of Professional Open Source.
3 | * Copyright 2018, Red Hat, Inc., and individual contributors
4 | * as indicated by the @author tags. See the copyright.txt file in the
5 | * distribution for a full listing of individual contributors.
6 | *
7 | * This is free software; you can redistribute it and/or modify it
8 | * under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation; either version 2.1 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * This software is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 | * Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public
18 | * License along with this software; if not, write to the Free
19 | * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 | * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 | */
22 |
23 | package io.smallrye.config.test.provider;
24 |
25 | import jakarta.inject.Inject;
26 | import jakarta.inject.Provider;
27 |
28 | import org.eclipse.microprofile.config.inject.ConfigProperty;
29 |
30 | /**
31 | * @author Jeff Mesnil (c) 2018 Red Hat inc.
32 | */
33 | public class ProviderBean {
34 |
35 | @Inject
36 | @ConfigProperty(name = "myEmail")
37 | Email email;
38 |
39 | @Inject
40 | @ConfigProperty(name = "myEmail")
41 | Provider emailProvider;
42 | }
43 |
--------------------------------------------------------------------------------
/testsuite/extra/src/test/java/io/smallrye/config/test/collections/broken/CollectionWithNoDefaultValueBean.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 Red Hat, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.smallrye.config.test.collections.broken;
18 |
19 | import java.util.List;
20 | import java.util.Set;
21 |
22 | import jakarta.inject.Inject;
23 |
24 | import org.eclipse.microprofile.config.inject.ConfigProperty;
25 |
26 | /**
27 | * @author Jeff Mesnil (c) 2018 Red Hat inc.
28 | */
29 | public class CollectionWithNoDefaultValueBean {
30 |
31 | @Inject
32 | @ConfigProperty(name = "myPets")
33 | private String[] arrayPets;
34 |
35 | @Inject
36 | @ConfigProperty(name = "myPets")
37 | private List listPets;
38 |
39 | @Inject
40 | @ConfigProperty(name = "myPets")
41 | private Set setPets;
42 |
43 | public String[] getArrayPets() {
44 | return arrayPets;
45 | }
46 |
47 | public List getListPets() {
48 | return listPets;
49 | }
50 |
51 | public Set getSetPets() {
52 | return setPets;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/testsuite/extra/src/test/java/io/smallrye/config/test/collections/KotlinCollectionsBeanTest.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config.test.collections;
2 |
3 | import static org.junit.jupiter.api.Assertions.assertEquals;
4 |
5 | import jakarta.inject.Inject;
6 |
7 | import org.jboss.arquillian.container.test.api.Deployment;
8 | import org.jboss.arquillian.junit5.ArquillianExtension;
9 | import org.jboss.shrinkwrap.api.ShrinkWrap;
10 | import org.jboss.shrinkwrap.api.asset.StringAsset;
11 | import org.jboss.shrinkwrap.api.spec.WebArchive;
12 | import org.junit.jupiter.api.Test;
13 | import org.junit.jupiter.api.extension.ExtendWith;
14 |
15 | @ExtendWith(ArquillianExtension.class)
16 | class KotlinCollectionsBeanTest {
17 | @Deployment
18 | static WebArchive deploy() {
19 | return ShrinkWrap
20 | .create(WebArchive.class)
21 | .addClasses(CollectionBean.class)
22 | .addClasses(KotlinCollectionsBean.class, KotlinCollectionsBeanTest.class)
23 | .addAsManifestResource("beans.xml")
24 | .addAsResource(new StringAsset("property.list=1,2,3\n" +
25 | "property.single=1234\n"),
26 | "META-INF/microprofile-config.properties");
27 | }
28 |
29 | @Inject
30 | KotlinCollectionsBean kotlinCollectionsBean;
31 |
32 | @Test
33 | void kotlinCollections() {
34 | assertEquals("1", kotlinCollectionsBean.typeList.get(0).getValue());
35 | assertEquals("2", kotlinCollectionsBean.typeList.get(1).getValue());
36 | assertEquals("3", kotlinCollectionsBean.typeList.get(2).getValue());
37 | assertEquals("1234", kotlinCollectionsBean.singleType.getValue());
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/utils/crypto/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 | smallrye-config-parent
6 | io.smallrye.config
7 | 3.15.1-SNAPSHOT
8 | ../../pom.xml
9 |
10 |
11 | smallrye-config-crypto
12 |
13 | SmallRye Config: Crypto
14 |
15 |
16 |
17 | io.smallrye.config
18 | smallrye-config
19 |
20 |
21 |
22 |
23 | org.junit.jupiter
24 | junit-jupiter
25 |
26 |
27 | io.smallrye.testing
28 | smallrye-testing-utilities
29 |
30 |
31 | jakarta.annotation
32 | jakarta.annotation-api
33 | test
34 |
35 |
36 | io.smallrye.config
37 | smallrye-config-source-keystore
38 | ${project.version}
39 | test
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/testsuite/extra/src/test/java/io/smallrye/config/test/secrets/MultipleSecretHandlersTest.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config.test.secrets;
2 |
3 | import static org.junit.jupiter.api.Assertions.assertEquals;
4 |
5 | import java.util.Map;
6 |
7 | import org.junit.jupiter.api.Test;
8 |
9 | import io.smallrye.config.PropertiesConfigSource;
10 | import io.smallrye.config.SmallRyeConfig;
11 | import io.smallrye.config.SmallRyeConfigBuilder;
12 |
13 | class MultipleSecretHandlersTest {
14 | @Test
15 | void multipleHandlers() {
16 | Map properties = Map.of(
17 | "smallrye.config.secret-handler.aes-gcm-nopadding.encryption-key",
18 | "c29tZWFyYml0cmFyeWNyYXp5c3RyaW5ndGhhdGRvZXNub3RtYXR0ZXI",
19 | "smallrye.config.secret-handler.aes-gcm-nopadding.encryption-key-decode", "true",
20 | "aes-gcm-nopadding.secret", "${aes-gcm-nopadding::DJNrZ6LfpupFv6QbXyXhvzD8eVDnDa_kTliQBpuzTobDZxlg}",
21 | "smallrye.config.secret-handler.jasypt.password", "jasypt",
22 | "smallrye.config.secret-handler.jasypt.algorithm", "PBEWithHMACSHA512AndAES_256",
23 | "jasypt.secret", "${jasypt::ENC(wqp8zDeiCQ5JaFvwDtoAcr2WMLdlD0rjwvo8Rh0thG5qyTQVGxwJjBIiW26y0dtU)}");
24 |
25 | SmallRyeConfig config = new SmallRyeConfigBuilder()
26 | .addDefaultInterceptors()
27 | .addDiscoveredSecretKeysHandlers()
28 | .withSources(new PropertiesConfigSource(properties, "", 0))
29 | .build();
30 |
31 | assertEquals("decoded", config.getConfigValue("aes-gcm-nopadding.secret").getValue());
32 | assertEquals("12345678", config.getConfigValue("jasypt.secret").getValue());
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/utils/jasypt/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 | smallrye-config-parent
6 | io.smallrye.config
7 | 3.15.1-SNAPSHOT
8 | ../../pom.xml
9 |
10 |
11 | smallrye-config-jasypt
12 |
13 | SmallRye Config: Jasypt
14 |
15 |
16 | 1.9.3
17 |
18 |
19 |
20 |
21 | io.smallrye.config
22 | smallrye-config
23 |
24 |
25 | org.jasypt
26 | jasypt
27 | ${version.jasypt}
28 |
29 |
30 |
31 |
32 | org.junit.jupiter
33 | junit-jupiter
34 |
35 |
36 | io.smallrye.testing
37 | smallrye-testing-utilities
38 |
39 |
40 | jakarta.annotation
41 | jakarta.annotation-api
42 | test
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/cdi/src/main/java/io/smallrye/config/inject/SecuritySupport.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 Red Hat, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.smallrye.config.inject;
18 |
19 | import java.security.AccessController;
20 | import java.security.PrivilegedAction;
21 |
22 | import io.smallrye.config._private.ConfigLogging;
23 |
24 | /**
25 | * @author Jeff Mesnil (c) 2018 Red Hat inc.
26 | */
27 | class SecuritySupport {
28 | private SecuritySupport() {
29 | }
30 |
31 | static ClassLoader getContextClassLoader() {
32 | if (System.getSecurityManager() == null) {
33 | return Thread.currentThread().getContextClassLoader();
34 | } else {
35 | return AccessController.doPrivileged((PrivilegedAction) () -> {
36 | ClassLoader tccl = null;
37 | try {
38 | tccl = Thread.currentThread().getContextClassLoader();
39 | } catch (SecurityException ex) {
40 | ConfigLogging.log.failedToRetrieveClassloader(ex);
41 | }
42 | return tccl;
43 | });
44 | }
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/documentation/src/main/docs/extensions/relocate.md:
--------------------------------------------------------------------------------
1 | # Relocate
2 |
3 | The `io.smallrye.config.RelocateConfigSourceInterceptor` allows to relocate a configuration name to another name, by
4 | providing a transformation function or just a simple key value map.
5 |
6 | When a configuration key is renamed, lookup needs to happen on the new name, but also on the old name if the
7 | config sources are not updated yet. The relocation function gives priority to the new resolved configuration name or
8 | resolves to the old name if no value is found under the new relocation name.
9 |
10 | ```java
11 | package org.acme.config;
12 |
13 | import io.smallrye.config.RelocateConfigSourceInterceptor;
14 |
15 | public class MicroProfileConfigRelocateInterceptor extends RelocateConfigSourceInterceptor {
16 | public MicroProfileConfigRelocateInterceptor() {
17 | super(name -> name.startsWith("mp.config") ?
18 | name.replaceAll("mp\\.config", "smallrye.config") :
19 | name);
20 | }
21 | }
22 | ```
23 |
24 | And registration in:
25 |
26 | ```properties title="META-INF/services/io.smallrye.config.ConfigSourceInterceptor"
27 | org.acme.config.MicroProfileConfigRelocateInterceptor
28 | ```
29 |
30 | The `MicroProfileConfigRelocateInterceptor` can relocate configuration names in the `mp.config` namespace
31 | to the `smallrye.config` namespace.
32 |
33 | !!! example
34 |
35 | ```properties title="application.properties"
36 | mp.config.profile=test
37 | smallrye.config.profile=prod
38 | ```
39 |
40 | A lookup to `mp.config.profile` returns the value `prod`. The config finds a valid value in the relocated name
41 | `smallrye.config.profile`, so the interceptor will use this value instead of the one in `mp.config.profile`.
42 |
--------------------------------------------------------------------------------
/utils/cdi-provider/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 |
6 | io.smallrye.config
7 | smallrye-config-parent
8 | 3.15.1-SNAPSHOT
9 | ../../
10 |
11 |
12 | smallrye-config-source-injection
13 |
14 | SmallRye Config: CDI ConfigSource Injection
15 |
16 |
17 |
18 | jakarta.enterprise
19 | jakarta.enterprise.cdi-api
20 | provided
21 |
22 |
23 |
24 | org.eclipse.microprofile.config
25 | microprofile-config-api
26 | provided
27 |
28 |
29 |
30 |
31 | org.junit.jupiter
32 | junit-jupiter
33 |
34 |
35 |
36 | org.jboss.weld
37 | weld-junit5
38 |
39 |
40 |
41 | io.smallrye.config
42 | smallrye-config
43 | test
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/documentation/src/main/docs/config/secret-handlers/jasypt.java:
--------------------------------------------------------------------------------
1 | ///usr/bin/env jbang "$0" "$@" ; exit $?
2 | //DEPS info.picocli:picocli:4.5.0
3 | //DEPS org.jasypt:jasypt:1.9.3
4 |
5 | import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;
6 | import org.jasypt.iv.RandomIvGenerator;
7 | import org.jasypt.properties.PropertyValueEncryptionUtils;
8 | import picocli.CommandLine;
9 | import picocli.CommandLine.Command;
10 | import picocli.CommandLine.Option;
11 | import picocli.CommandLine.Parameters;
12 |
13 | import java.util.concurrent.Callable;
14 | import java.util.logging.Logger;
15 |
16 | @Command(name = "jasypt", mixinStandardHelpOptions = true)
17 | class jasypt implements Callable {
18 | @Option(names = {"-s", "--secret" }, description = "Secret", required = true)
19 | private String secret;
20 | @Option(names = {"-p", "--password" }, description = "Password", required = true)
21 | private String password;
22 | @Option(names = {"-a", "--algorithm" }, description = "Algorithm", defaultValue = "PBEWithHMACSHA512AndAES_256")
23 | private String algorithm;
24 |
25 | public static void main(String... args) {
26 | int exitCode = new CommandLine(new jasypt()).execute(args);
27 | System.exit(exitCode);
28 | }
29 |
30 | @Override
31 | public Integer call() {
32 | StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
33 | encryptor.setPassword(password);
34 | encryptor.setAlgorithm(algorithm);
35 | encryptor.setIvGenerator(new RandomIvGenerator());
36 | encryptor.initialize();
37 |
38 | String encrypt = PropertyValueEncryptionUtils.encrypt(secret, encryptor);
39 | System.out.println("${jasypt::" + encrypt + "}");
40 |
41 | return 0;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/implementation/src/main/java/io/smallrye/config/FallbackConfigSourceInterceptor.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config;
2 |
3 | import static io.smallrye.config.ConfigValue.CONFIG_SOURCE_COMPARATOR;
4 |
5 | import java.io.Serial;
6 | import java.util.Map;
7 | import java.util.function.Function;
8 |
9 | import jakarta.annotation.Priority;
10 |
11 | @Priority(Priorities.LIBRARY + 600)
12 | public class FallbackConfigSourceInterceptor extends AbstractMappingConfigSourceInterceptor {
13 | @Serial
14 | private static final long serialVersionUID = 1472367702046537565L;
15 |
16 | public FallbackConfigSourceInterceptor(final Function mapping) {
17 | super(mapping);
18 | }
19 |
20 | public FallbackConfigSourceInterceptor(final Map mappings) {
21 | super(mappings);
22 | }
23 |
24 | @Override
25 | public ConfigValue getValue(final ConfigSourceInterceptorContext context, final String name) {
26 | ConfigValue configValue = context.proceed(name);
27 | String map = getMapping().apply(name);
28 |
29 | if (name.equals(map)) {
30 | return configValue;
31 | }
32 |
33 | ConfigValue fallbackValue = context.proceed(map);
34 | // Check which one comes from a higher ordinal source
35 | if (configValue != null && fallbackValue != null) {
36 | return CONFIG_SOURCE_COMPARATOR.compare(configValue, fallbackValue) >= 0 ? configValue
37 | : fallbackValue.withName(name);
38 | } else {
39 | if (configValue != null) {
40 | return configValue;
41 | } else if (fallbackValue != null) {
42 | return fallbackValue.withName(name);
43 | }
44 | return null;
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/implementation/src/main/java/io/smallrye/config/RelocateConfigSourceInterceptor.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config;
2 |
3 | import static io.smallrye.config.ConfigValue.CONFIG_SOURCE_COMPARATOR;
4 |
5 | import java.io.Serial;
6 | import java.util.Map;
7 | import java.util.function.Function;
8 |
9 | import jakarta.annotation.Priority;
10 |
11 | @Priority(Priorities.LIBRARY + 300)
12 | public class RelocateConfigSourceInterceptor extends AbstractMappingConfigSourceInterceptor {
13 | @Serial
14 | private static final long serialVersionUID = 3476637906383945843L;
15 |
16 | public RelocateConfigSourceInterceptor(final Function mapping) {
17 | super(mapping);
18 | }
19 |
20 | public RelocateConfigSourceInterceptor(final Map mappings) {
21 | super(mappings);
22 | }
23 |
24 | @Override
25 | public ConfigValue getValue(final ConfigSourceInterceptorContext context, final String name) {
26 | String map = getMapping().apply(name);
27 | ConfigValue relocateValue = context.proceed(map);
28 |
29 | if (name.equals(map)) {
30 | return relocateValue;
31 | }
32 |
33 | ConfigValue configValue = context.proceed(name);
34 | // Check which one comes from a higher ordinal source
35 | if (relocateValue != null && configValue != null) {
36 | return CONFIG_SOURCE_COMPARATOR.compare(relocateValue, configValue) >= 0 ? relocateValue
37 | : configValue.withName(map);
38 | } else {
39 | if (relocateValue != null) {
40 | return relocateValue;
41 | } else if (configValue != null) {
42 | return configValue.withName(map);
43 | }
44 | return null;
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/validator/src/test/java/io/smallrye/config/validator/KeyValuesConfigSource.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config.validator;
2 |
3 | import java.io.Serializable;
4 | import java.util.Collections;
5 | import java.util.HashMap;
6 | import java.util.Map;
7 | import java.util.Set;
8 |
9 | import org.eclipse.microprofile.config.spi.ConfigSource;
10 |
11 | public class KeyValuesConfigSource implements ConfigSource, Serializable {
12 |
13 | private final Map properties = new HashMap<>();
14 |
15 | private KeyValuesConfigSource(Map properties) {
16 | this.properties.putAll(properties);
17 | }
18 |
19 | @Override
20 | public Map getProperties() {
21 | return Collections.unmodifiableMap(properties);
22 | }
23 |
24 | @Override
25 | public Set getPropertyNames() {
26 | return Collections.unmodifiableSet(properties.keySet());
27 | }
28 |
29 | @Override
30 | public String getValue(String propertyName) {
31 | return properties.get(propertyName);
32 | }
33 |
34 | @Override
35 | public String getName() {
36 | return "KeyValuesConfigSource";
37 | }
38 |
39 | public static ConfigSource config(Map properties) {
40 | return new KeyValuesConfigSource(properties);
41 | }
42 |
43 | public static ConfigSource config(String... keyValues) {
44 | if (keyValues.length % 2 != 0) {
45 | throw new IllegalArgumentException("keyValues array must be a multiple of 2");
46 | }
47 |
48 | Map props = new HashMap<>();
49 | for (int i = 0; i < keyValues.length; i += 2) {
50 | props.put(keyValues[i], keyValues[i + 1]);
51 | }
52 | return new KeyValuesConfigSource(props);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/examples/mapping/src/main/java/io/smallrye/config/examples/mapping/Server.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config.examples.mapping;
2 |
3 | import java.time.Duration;
4 | import java.util.List;
5 | import java.util.Map;
6 | import java.util.Optional;
7 |
8 | import io.smallrye.config.ConfigMapping;
9 | import io.smallrye.config.WithConverter;
10 | import io.smallrye.config.WithDefault;
11 | import io.smallrye.config.WithName;
12 |
13 | @ConfigMapping(prefix = "server")
14 | public interface Server {
15 | String host();
16 |
17 | int port();
18 |
19 | @WithConverter(DurationConverter.class)
20 | Duration timeout();
21 |
22 | @WithName("io-threads")
23 | int threads();
24 |
25 | Map form();
26 |
27 | Optional ssl();
28 |
29 | Optional proxy();
30 |
31 | Optional cors();
32 |
33 | Log log();
34 |
35 | interface Ssl {
36 | int port();
37 |
38 | String certificate();
39 |
40 | @WithDefault("TLSv1.3,TLSv1.2")
41 | List protocols();
42 | }
43 |
44 | interface Proxy {
45 | boolean enable();
46 | }
47 |
48 | interface Log {
49 | @WithDefault("false")
50 | boolean enabled();
51 |
52 | @WithDefault(".log")
53 | String suffix();
54 |
55 | @WithDefault("true")
56 | boolean rotate();
57 |
58 | @WithDefault("COMMON")
59 | Pattern pattern();
60 |
61 | enum Pattern {
62 | COMMON,
63 | SHORT,
64 | COMBINED,
65 | LONG;
66 | }
67 | }
68 |
69 | interface Cors {
70 | List origins();
71 |
72 | List methods();
73 |
74 | interface Origin {
75 | String host();
76 |
77 | int port();
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/examples/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 | 4.0.0
19 |
20 |
21 | io.smallrye.config
22 | smallrye-config-parent
23 | 3.15.1-SNAPSHOT
24 |
25 |
26 | smallrye-config-examples
27 | pom
28 |
29 | SmallRye Config Examples
30 |
31 |
32 | interceptors
33 | expansion
34 | profiles
35 | configmap
36 | mapping
37 |
38 |
39 |
40 |
41 |
42 | org.apache.maven.plugins
43 | maven-install-plugin
44 |
45 | true
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/testsuite/extra/src/test/java/io/smallrye/config/test/source/MultiplePropertiesConfigSourceTest.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config.test.source;
2 |
3 | import static org.junit.jupiter.api.Assertions.assertEquals;
4 |
5 | import jakarta.inject.Inject;
6 |
7 | import org.eclipse.microprofile.config.Config;
8 | import org.jboss.arquillian.container.test.api.Deployment;
9 | import org.jboss.arquillian.junit5.ArquillianExtension;
10 | import org.jboss.shrinkwrap.api.ShrinkWrap;
11 | import org.jboss.shrinkwrap.api.asset.StringAsset;
12 | import org.jboss.shrinkwrap.api.spec.JavaArchive;
13 | import org.jboss.shrinkwrap.api.spec.WebArchive;
14 | import org.junit.jupiter.api.Test;
15 | import org.junit.jupiter.api.extension.ExtendWith;
16 |
17 | @ExtendWith(ArquillianExtension.class)
18 | public class MultiplePropertiesConfigSourceTest {
19 | @Deployment
20 | public static WebArchive deploy() {
21 | JavaArchive sourceOne = ShrinkWrap
22 | .create(JavaArchive.class, "source-one.jar")
23 | .addAsManifestResource(new StringAsset("my.prop.one=1234"), "microprofile-config.properties")
24 | .as(JavaArchive.class);
25 |
26 | JavaArchive sourceTwo = ShrinkWrap
27 | .create(JavaArchive.class, "source-two.jar")
28 | .addAsManifestResource(new StringAsset("my.prop.two=1234"), "microprofile-config.properties")
29 | .as(JavaArchive.class);
30 |
31 | return ShrinkWrap
32 | .create(WebArchive.class, "sources.war")
33 | .addAsLibraries(sourceOne, sourceTwo);
34 | }
35 |
36 | @Inject
37 | Config config;
38 |
39 | @Test
40 | void multiple() {
41 | assertEquals("1234", config.getValue("my.prop.one", String.class));
42 | assertEquals("1234", config.getValue("my.prop.two", String.class));
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/documentation/src/main/docs/config/customizer.md:
--------------------------------------------------------------------------------
1 | # Customizer
2 |
3 | A `SmallRyeConfigBuilderCustomizer` allows to customize a `SmallRyeConfigBuilder`, used to create the `SmallRyeConfig`
4 | instance.
5 |
6 | Registration of a `SmallRyeConfigBuilderCustomizer` is done via the `ServiceLoader` mechanism by providing the
7 | implementation classes in a `META-INF/services/io.smallrye.config.SmallRyeConfigBuilderCustomizer` file. Alternatively,
8 | customizers may be registered via the Programmatic API in `SmallRyeConfigBuilder#withCustomizers`.
9 |
10 | The `SmallRyeConfigBuilderCustomizer` may also
11 | assign a priority by overriding the default method `int priority()`. Customizers are sorted by ascending priority and
12 | executed in that order, meaning that higher numeric priorities will execute last, possible overriding values set by
13 | previous customizers.
14 |
15 | ```java title="CustomConfigBuilder"
16 | package org.acme.config;
17 |
18 | import io.smallrye.config.SmallRyeConfigBuilder;
19 | import io.smallrye.config.SmallRyeConfigBuilderCustomizer;
20 |
21 | public class CustomConfigBuilder implements SmallRyeConfigBuilderCustomizer {
22 | @Override
23 | public void configBuilder(final SmallRyeConfigBuilder builder) {
24 | builder.withDefaultValue("my.default", "1234");
25 | }
26 | }
27 | ```
28 |
29 | And registration in:
30 |
31 | ```properties title="META-INF/services/io.smallrye.config.SmallRyeConfigBuilderCustomizer"
32 | org.acme.config.CustomConfigBuilder
33 | ```
34 |
35 | The `CustomConfigBuilder` will be executed when creating a new `SmallRyeConfig` from a `SmallRyeConfigBuilder`:
36 |
37 | ```java
38 | SmallRyeConfig config = new SmallRyeConfigBuilder().build();
39 | config.getValue("my.default", int.class);
40 | ```
41 |
42 | A look up to `my.default` returns the value `1234`, registered by the `CustomConfigBuilder`.
43 |
44 |
--------------------------------------------------------------------------------
/implementation/src/main/java/io/smallrye/config/ConfigurableConfigSource.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config;
2 |
3 | import java.util.ArrayList;
4 | import java.util.HashMap;
5 | import java.util.HashSet;
6 | import java.util.List;
7 | import java.util.Map;
8 | import java.util.Set;
9 |
10 | import org.eclipse.microprofile.config.spi.ConfigSource;
11 |
12 | public class ConfigurableConfigSource implements ConfigSource {
13 | private final ConfigSourceFactory factory;
14 |
15 | public ConfigurableConfigSource(ConfigSourceFactory factory) {
16 | this.factory = factory;
17 | }
18 |
19 | @Override
20 | public Map getProperties() {
21 | return new HashMap<>();
22 | }
23 |
24 | @Override
25 | public Set getPropertyNames() {
26 | return new HashSet<>();
27 | }
28 |
29 | @Override
30 | public String getValue(final String propertyName) {
31 | return null;
32 | }
33 |
34 | @Override
35 | public String getName() {
36 | return factory.getClass().getName();
37 | }
38 |
39 | @Override
40 | public int getOrdinal() {
41 | return factory.getPriority().orElse(DEFAULT_ORDINAL);
42 | }
43 |
44 | ConfigSourceFactory getFactory() {
45 | return factory;
46 | }
47 |
48 | List getConfigSources(final ConfigSourceContext context) {
49 | final List configSources = new ArrayList<>();
50 | for (final ConfigSource configSource : factory.getConfigSources(context)) {
51 | if (configSource instanceof ConfigurableConfigSource) {
52 | configSources.addAll(((ConfigurableConfigSource) configSource).getConfigSources(context));
53 | } else {
54 | configSources.add(configSource);
55 | }
56 | }
57 | return configSources;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/testsuite/extra/src/test/java/io/smallrye/config/test/provider/Email.java:
--------------------------------------------------------------------------------
1 | /*
2 | * JBoss, Home of Professional Open Source.
3 | * Copyright 2018, Red Hat, Inc., and individual contributors
4 | * as indicated by the @author tags. See the copyright.txt file in the
5 | * distribution for a full listing of individual contributors.
6 | *
7 | * This is free software; you can redistribute it and/or modify it
8 | * under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation; either version 2.1 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * This software is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 | * Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public
18 | * License along with this software; if not, write to the Free
19 | * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 | * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 | */
22 |
23 | package io.smallrye.config.test.provider;
24 |
25 | /**
26 | * @author Jeff Mesnil (c) 2018 Red Hat inc.
27 | */
28 | public class Email {
29 | private String name;
30 | private String domain;
31 |
32 | public Email(String value) {
33 | String[] components = value.split("@");
34 | if (components.length == 2) {
35 | name = components[0];
36 | domain = components[1];
37 | }
38 | }
39 |
40 | public String getName() {
41 | return name;
42 | }
43 |
44 | public String getDomain() {
45 | return domain;
46 | }
47 |
48 | public String toString() {
49 | return name + "(at)" + domain;
50 | }
51 | }
--------------------------------------------------------------------------------
/cdi/src/main/java/io/smallrye/config/inject/ConfigException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 Apache Software Foundation
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.smallrye.config.inject;
18 |
19 | import java.io.Serial;
20 |
21 | /**
22 | * A relatively generic Exception that encapsulates the configuration
23 | * property's name.
24 | *
25 | * @author Steve Moyer - The Pennsylvania State University
26 | */
27 | public class ConfigException extends Exception {
28 | @Serial
29 | private static final long serialVersionUID = 1L;
30 |
31 | private final String configPropertyName;
32 |
33 | /**
34 | * Constructor for {@link InjectionMessages#noConfigValue(String, String)}
35 | */
36 | public ConfigException(String message, String configPropertyName) {
37 | super(message);
38 | this.configPropertyName = configPropertyName;
39 | }
40 |
41 | /**
42 | * Constructor for {@link InjectionMessages#retrieveConfigFailure(String, String, String, Exception)}
43 | */
44 | public ConfigException(String message, String configPropertyName, Throwable cause) {
45 | super(message, cause);
46 | this.configPropertyName = configPropertyName;
47 | }
48 |
49 | public String getConfigPropertyName() {
50 | return configPropertyName;
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/documentation/src/main/docs/config-sources/filesystem.md:
--------------------------------------------------------------------------------
1 | # FileSystem Config Source
2 |
3 | This Config Source loads configuration values for each file found in a directory. Each file corresponds to a single
4 | property, where the file name is the configuration property name and the file content the configuration value.
5 |
6 | For instance, if a directory structure looks like:
7 |
8 | foo/
9 | |__num.max
10 | |__num.size
11 |
12 | The `FileSystem` Config Source will provide 2 properties:
13 |
14 | - num.max
15 | - num.size
16 |
17 | !!! warning
18 |
19 | Nested directories are not supported.
20 |
21 | This Config Source can be used to read configuration from
22 | [Kubernetes ConfigMap](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap). Check the
23 | [Kubernetes ConfigMap ConfigSource Example](https://github.com/smallrye/smallrye-config/blob/main/examples/configmap/README.adoc).
24 |
25 | The same mapping rules as defined for environment variables are applied, so the `FileSystem` Config Source will search
26 | for a given property name `num.max`:
27 |
28 | - Exact match (`num.max`)
29 | - Replace each character that is neither alphanumeric nor \_ with \_ (`num_max`)
30 | - Replace each character that is neither alphanumeric nor \_ with \_; then convert the name to upper case (`NUM_MAX`)
31 |
32 | The following dependency is required in the classpath to use the `FileSystem` Config Source:
33 |
34 | ```xml
35 |
36 | io.smallrye.config
37 | smallrye-config-source-file-system
38 | {{attributes['version']}}
39 |
40 | ```
41 |
42 | The configuration property `smallrye.config.source.file.locations` sets the directory paths to look up the files. It
43 | accepts multiple locations separated by a comma and each must represent a valid URI to a directory.
44 |
--------------------------------------------------------------------------------
/documentation/src/main/docs/extensions/fallback.md:
--------------------------------------------------------------------------------
1 | # Fallback
2 |
3 | The `io.smallrye.config.FallbackConfigSourceInterceptor` allows to fall back to another configuration name, by
4 | providing a transformation function or just a simple key value map.
5 |
6 | When a configuration name does not exist, there might be another configuration name that the config can
7 | fall back to provide the same expected behavior. The fallback function is only applied if the original resolved
8 | configuration name is not found and resolved to the fallback name.
9 |
10 | ```java
11 | package org.acme.config;
12 |
13 | import io.smallrye.config.FallbackConfigSourceInterceptor;
14 |
15 | public class MicroProfileConfigFallbackInterceptor extends FallbackConfigSourceInterceptor {
16 | public MicroProfileConfigFallbackInterceptor() {
17 | super(name -> name.startsWith("mp.config") ?
18 | name.replaceAll("mp\\.config", "smallrye.config") :
19 | name);
20 | }
21 | }
22 | ```
23 |
24 | And registration in:
25 |
26 | ```properties title="META-INF/services/io.smallrye.config.ConfigSourceInterceptor"
27 | org.acme.config.MicroProfileConfigFallbackInterceptor
28 | ```
29 |
30 | The `MicroProfileConfigFallbackInterceptor` can fallback configuration names in the `mp.config` namespace
31 | to the `smallrye.config` namespace.
32 |
33 | !!! example
34 |
35 | ```properties title="application.properties"
36 | mp.config.profile=test
37 | smallrye.config.profile=prod
38 | ```
39 |
40 | A lookup to `mp.config.profile` returns the value `test`.
41 |
42 | ```properties title="application.properties"
43 | smallrye.config.profile=prod
44 | ```
45 |
46 | A lookup to `mp.config.profile` returns the value `prod`. The config is not able to find a value for
47 | `mp.config.profile`, so the interceptor fallbacks and lookups the value of `smallrye.config.profile`.
48 |
--------------------------------------------------------------------------------
/examples/configmap/src/main/java/io/smallrye/config/examples/configmap/ConfigMapApp.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config.examples.configmap;
2 |
3 | import java.net.InetSocketAddress;
4 | import java.util.Map;
5 |
6 | import org.eclipse.microprofile.config.Config;
7 | import org.eclipse.microprofile.config.ConfigProvider;
8 | import org.eclipse.microprofile.config.spi.ConfigSource;
9 |
10 | import com.sun.net.httpserver.HttpServer;
11 |
12 | public class ConfigMapApp {
13 | public static void main(String[] args) throws Exception {
14 | Config config = ConfigProvider.getConfig();
15 |
16 | HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);
17 | server.createContext("/configMap", exchange -> {
18 | boolean responseSent = false;
19 |
20 | final Iterable configSources = config.getConfigSources();
21 | for (ConfigSource configSource : configSources) {
22 | if (configSource.getName().startsWith("FileSystemConfig")) {
23 | final Map properties = configSource.getProperties();
24 | final byte[] bytes = properties.toString().getBytes();
25 | exchange.sendResponseHeaders(200, properties.toString().length());
26 | exchange.getResponseBody().write(bytes);
27 | exchange.getResponseBody().flush();
28 | exchange.getResponseBody().close();
29 | responseSent = true;
30 | break;
31 | }
32 | }
33 |
34 | if (!responseSent) {
35 | exchange.sendResponseHeaders(404, 0);
36 | exchange.getResponseBody().write(new byte[0]);
37 | exchange.getResponseBody().flush();
38 | exchange.getResponseBody().close();
39 | }
40 | });
41 |
42 | server.start();
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/implementation/src/test/java/io/smallrye/config/ConfigValueConfigSourceWrapperTest.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config;
2 |
3 | import static org.junit.jupiter.api.Assertions.*;
4 |
5 | import java.util.Map;
6 | import java.util.Set;
7 |
8 | import org.junit.jupiter.api.Test;
9 |
10 | class ConfigValueConfigSourceWrapperTest {
11 | @Test
12 | void getConfigValue() {
13 | ConfigValue configValue = config().getConfigValue("my.prop");
14 | assertNotNull(configValue);
15 | assertEquals("1234", configValue.getValue());
16 | assertEquals("1234", configValue.getRawValue());
17 | }
18 |
19 | @Test
20 | void getConfigValueProperties() {
21 | Map map = config().getConfigValueProperties();
22 | assertEquals(1, map.size());
23 | assertTrue(map.containsKey("my.prop"));
24 | assertEquals("1234", map.get("my.prop").getValue());
25 | }
26 |
27 | @Test
28 | void getProperties() {
29 | final Map map = config().getProperties();
30 | assertEquals(1, map.size());
31 | assertTrue(map.containsKey("my.prop"));
32 | }
33 |
34 | @Test
35 | void getValue() {
36 | assertEquals("1234", config().getValue("my.prop"));
37 | }
38 |
39 | @Test
40 | void getPropertyNames() {
41 | final Set names = config().getPropertyNames();
42 | assertEquals(1, names.size());
43 | assertEquals("my.prop", names.iterator().next());
44 | }
45 |
46 | @Test
47 | void getName() {
48 | assertEquals("KeyValuesConfigSource", config().getName());
49 | }
50 |
51 | @Test
52 | void getOrdinal() {
53 | assertEquals(100, config().getOrdinal());
54 | }
55 |
56 | private static ConfigValueConfigSource config() {
57 | return SmallRyeConfigSources.ConfigValueConfigSourceWrapper.wrap(KeyValuesConfigSource.config("my.prop", "1234"));
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/implementation/src/main/java/io/smallrye/config/LoggingConfigSourceInterceptor.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config;
2 |
3 | import static io.smallrye.config.SecretKeys.doLocked;
4 |
5 | import java.io.Serial;
6 |
7 | import jakarta.annotation.Priority;
8 |
9 | import io.smallrye.config._private.ConfigLogging;
10 |
11 | @Priority(Priorities.LIBRARY + 250)
12 | public class LoggingConfigSourceInterceptor implements ConfigSourceInterceptor {
13 | @Serial
14 | private static final long serialVersionUID = 367246512037404779L;
15 |
16 | private final boolean enabled;
17 |
18 | public LoggingConfigSourceInterceptor() {
19 | this(true);
20 | }
21 |
22 | public LoggingConfigSourceInterceptor(final boolean enabled) {
23 | this.enabled = enabled;
24 | }
25 |
26 | @Override
27 | public ConfigValue getValue(final ConfigSourceInterceptorContext context, final String name) {
28 | if (!enabled || !ConfigLogging.log.isDebugEnabled()) {
29 | return context.proceed(name);
30 | }
31 |
32 | try {
33 | // Unlocked keys will run here.
34 | ConfigValue configValue = doLocked(() -> context.proceed(name));
35 | if (configValue != null) {
36 | ConfigLogging.log.lookup(configValue.getName(), configValue.getLocation(), configValue.getValue());
37 | } else {
38 | ConfigLogging.log.notFound(name);
39 | }
40 | return configValue;
41 | } catch (SecurityException e) {
42 | // Handled next, to omit the values to log from the secret.
43 | }
44 |
45 | // Locked keys here.
46 | final ConfigValue secret = context.proceed(name);
47 | if (secret != null) {
48 | ConfigLogging.log.lookup(secret.getName(), "secret", "secret");
49 | } else {
50 | ConfigLogging.log.notFound(name);
51 | }
52 | return secret;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/testsuite/extra/src/test/java/io/smallrye/config/test/source/MultipleProfilePropertiesConfigSourceTest.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config.test.source;
2 |
3 | import static org.junit.jupiter.api.Assertions.assertEquals;
4 |
5 | import jakarta.inject.Inject;
6 |
7 | import org.eclipse.microprofile.config.Config;
8 | import org.jboss.arquillian.container.test.api.Deployment;
9 | import org.jboss.arquillian.junit5.ArquillianExtension;
10 | import org.jboss.shrinkwrap.api.ShrinkWrap;
11 | import org.jboss.shrinkwrap.api.asset.StringAsset;
12 | import org.jboss.shrinkwrap.api.spec.JavaArchive;
13 | import org.jboss.shrinkwrap.api.spec.WebArchive;
14 | import org.junit.jupiter.api.Test;
15 | import org.junit.jupiter.api.extension.ExtendWith;
16 |
17 | @ExtendWith(ArquillianExtension.class)
18 | class MultipleProfilePropertiesConfigSourceTest {
19 | @Deployment
20 | static WebArchive deploy() {
21 | JavaArchive sourceOne = ShrinkWrap
22 | .create(JavaArchive.class)
23 | .addAsManifestResource(new StringAsset("smallrye.config.profile=prod"), "microprofile-config.properties")
24 | .addAsManifestResource(new StringAsset("my.prop.one=1234"), "microprofile-config-prod.properties")
25 | .as(JavaArchive.class);
26 |
27 | JavaArchive sourceTwo = ShrinkWrap
28 | .create(JavaArchive.class)
29 | .addAsManifestResource(new StringAsset("my.prop.two=1234"), "microprofile-config-prod.properties")
30 | .as(JavaArchive.class);
31 |
32 | return ShrinkWrap
33 | .create(WebArchive.class, "sources.war")
34 | .addAsLibraries(sourceOne, sourceTwo);
35 | }
36 |
37 | @Inject
38 | Config config;
39 |
40 | @Test
41 | void multiple() {
42 | assertEquals("1234", config.getValue("my.prop.one", String.class));
43 | assertEquals("1234", config.getValue("my.prop.two", String.class));
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/sources/yaml/src/test/java/io/smallrye/config/source/yaml/BasicTest.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config.source.yaml;
2 |
3 | import static org.junit.jupiter.api.Assertions.assertEquals;
4 | import static org.junit.jupiter.api.Assertions.assertNotNull;
5 |
6 | import org.eclipse.microprofile.config.spi.ConfigSource;
7 | import org.junit.jupiter.api.Test;
8 |
9 | class BasicTest {
10 | @Test
11 | void basicKeyValue() {
12 | String yaml = "foo:\n"
13 | + " bar:\n"
14 | + " baz: something\n"
15 | + " zap: something else \n";
16 |
17 | ConfigSource src = new YamlConfigSource("Yaml", yaml);
18 |
19 | assertEquals("something", src.getValue("foo.bar.baz"));
20 | assertEquals("something else", src.getValue("foo.bar.zap"));
21 | }
22 |
23 | @Test
24 | void nullKeyValue() {
25 | String yaml = "foo:\n"
26 | + " ~: something\n";
27 |
28 | ConfigSource src = new YamlConfigSource("Yaml", yaml);
29 |
30 | assertEquals("something", src.getValue("foo"));
31 | }
32 |
33 | @Test
34 | void listValue() {
35 | String yaml = "foo:\n"
36 | + " bar:\n"
37 | + " ~:\n"
38 | + " - cat\n"
39 | + " - dog\n"
40 | + " - chicken\n";
41 |
42 | ConfigSource src = new YamlConfigSource("Yaml", yaml);
43 |
44 | assertEquals("cat,dog,chicken", src.getValue("foo.bar"));
45 | }
46 |
47 | @Test
48 | void emptyFile() {
49 | ConfigSource src = new YamlConfigSource("Yaml", "");
50 | assertNotNull(src, "Should create config source for empty file correctly");
51 | }
52 |
53 | @Test
54 | void preserveOriginal() {
55 | ConfigSource source = new YamlConfigSource("Yaml", "date: 2010-10-10");
56 | assertEquals("2010-10-10", source.getValue("date"));
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/implementation/src/main/java/io/smallrye/config/ConfigSourceContext.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config;
2 |
3 | import java.util.HashSet;
4 | import java.util.Iterator;
5 | import java.util.List;
6 | import java.util.Set;
7 |
8 | import org.eclipse.microprofile.config.spi.ConfigSource;
9 |
10 | /**
11 | * Exposes contextual information on the ConfigSource initialization via {@link ConfigSourceFactory}.
12 | */
13 | public interface ConfigSourceContext {
14 | ConfigValue getValue(String name);
15 |
16 | Iterator iterateNames();
17 |
18 | default List getProfiles() {
19 | throw new UnsupportedOperationException();
20 | }
21 |
22 | default List getConfigSources() {
23 | throw new UnsupportedOperationException();
24 | }
25 |
26 | class ConfigSourceContextConfigSource implements ConfigSource {
27 | private final ConfigSourceContext context;
28 |
29 | public ConfigSourceContextConfigSource(final ConfigSourceContext context) {
30 | this.context = context;
31 | }
32 |
33 | @Override
34 | public Set getPropertyNames() {
35 | Set names = new HashSet<>();
36 | Iterator namesIterator = context.iterateNames();
37 | while (namesIterator.hasNext()) {
38 | names.add(namesIterator.next());
39 | }
40 | return names;
41 | }
42 |
43 | @Override
44 | public String getValue(final String propertyName) {
45 | ConfigValue value = context.getValue(propertyName);
46 | return value != null && value.getValue() != null ? value.getValue() : null;
47 | }
48 |
49 | @Override
50 | public String getName() {
51 | return ConfigSourceContextConfigSource.class.getName();
52 | }
53 |
54 | @Override
55 | public int getOrdinal() {
56 | return Integer.MAX_VALUE;
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/documentation/src/main/docs/assets/smallrye-icon.svg:
--------------------------------------------------------------------------------
1 |
22 |
--------------------------------------------------------------------------------
/implementation/src/test/java/io/smallrye/config/MultiValueTest.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config;
2 |
3 | import static org.junit.jupiter.api.Assertions.assertEquals;
4 | import static org.junit.jupiter.api.Assertions.assertNotNull;
5 | import static org.junit.jupiter.api.Assertions.assertTrue;
6 |
7 | import java.util.ArrayList;
8 | import java.util.Arrays;
9 | import java.util.HashSet;
10 | import java.util.List;
11 | import java.util.Map;
12 | import java.util.Set;
13 | import java.util.TreeSet;
14 |
15 | import org.junit.jupiter.api.BeforeEach;
16 | import org.junit.jupiter.api.Test;
17 |
18 | class MultiValueTest {
19 |
20 | SmallRyeConfig config;
21 |
22 | @BeforeEach
23 | void setUp() {
24 | config = SmallRyeConfigProviderResolver.instance().getBuilder()
25 | .withSources(new PropertiesConfigSource(Map.of("my.pets", "snake,dog,cat,cat"), "my properties"))
26 | .build()
27 | .unwrap(SmallRyeConfig.class);
28 | }
29 |
30 | @Test
31 | void getValuesAsList() {
32 | List pets = config.getValues("my.pets", String.class, ArrayList::new);
33 | assertNotNull(pets);
34 | assertEquals(4, pets.size());
35 | assertEquals(Arrays.asList("snake", "dog", "cat", "cat"), pets);
36 | }
37 |
38 | @Test
39 | void getValuesAsSet() {
40 | Set pets = config.getValues("my.pets", String.class, HashSet::new);
41 | assertNotNull(pets);
42 | assertEquals(3, pets.size());
43 | assertTrue(pets.contains("snake"));
44 | assertTrue(pets.contains("dog"));
45 | assertTrue(pets.contains("cat"));
46 | }
47 |
48 | @Test
49 | void getValuesAsSortedSet() {
50 | Set pets = config.getValues("my.pets", String.class, s -> new TreeSet<>(String.CASE_INSENSITIVE_ORDER));
51 | assertNotNull(pets);
52 | assertEquals(3, pets.size());
53 | assertEquals(Arrays.asList("cat", "dog", "snake"), new ArrayList<>(pets));
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/examples/configmap/README.adoc:
--------------------------------------------------------------------------------
1 | = Kubernetes ConfigMap ConfigSource Example
2 |
3 | In this example, the `FileSystemConfigSource` is used to access a Kubernetes ConfigMap configuration.
4 |
5 | == Setup
6 |
7 | Since the `FileSystemConfigSource` is implemented in a separate `SmallRyeConfig` module, it requires an additional
8 | dependency in the project that wants to read configuration from Kubernetes ConfigMap.
9 |
10 | [source,xml,subs="verbatim,attributes"]
11 | ----
12 |
13 | io.smallrye.config
14 | smallrye-config-source-file-system
15 | {version}
16 |
17 | ----
18 |
19 | == Registration
20 |
21 | The `smallrye-config-source-file-system` automatically registers a `FileSystemConfigSourceFactory` that accepts the
22 | configuration property `smallrye.config.source.file.location` to set the volume path and read the Kubernetes ConfigMap.
23 |
24 | Usually, an environment variable `SMALLRYE_CONFIG_SOURCE_FILE_LOCATION` sets the ConfigMap location in the Kubernetes
25 | file descriptor.
26 |
27 | == Run
28 |
29 | The example starts a simple http server with a single endpoint im `/configMap`. To deploy the example in a Kubernetes
30 | cluster requires the following steps.
31 |
32 | Set up a local Docker Registry first to store the generated Docker images:
33 |
34 | [source,bash]
35 | ----
36 | docker run -d -p 5000:5000 --restart=always --name docker-registry registry:2
37 | ----
38 |
39 | Set up a host in '/etc/hosts' pointing `127.0.0.1` to `docker-registry`.
40 |
41 | Build the example with:
42 |
43 | [source,bash]
44 | ----
45 | mvn package docker:build docker:push
46 | ----
47 |
48 | Deploy to Kubernetes with:
49 |
50 | [source,bash]
51 | ----
52 | kubectl apply -f .kubernetes
53 | ----
54 |
55 | Call tbe endpoint `curl http://localhost:8080/configMap`. This should list all the configurations set in the Kubernets
56 | Config Map. The Kubernetes and ConfigMap configuration can be found in `.kubernetes/configmap-app.yml`.
57 |
--------------------------------------------------------------------------------
/common/src/test/java/io/smallrye/config/common/utils/ConfigSourceUtilTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 Red Hat, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.smallrye.config.common.utils;
17 |
18 | import static org.junit.jupiter.api.Assertions.assertEquals;
19 | import static org.junit.jupiter.api.Assertions.assertTrue;
20 |
21 | import java.util.Map;
22 | import java.util.Properties;
23 |
24 | import org.junit.jupiter.api.Test;
25 |
26 | class ConfigSourceUtilTest {
27 | @Test
28 | void propertiesToMap() {
29 | Properties properties = new Properties();
30 | properties.put("my.key1", "my.value1");
31 | properties.put("my.key2", "my.value2");
32 | properties.put("my.key3", 2);
33 |
34 | Map map = ConfigSourceUtil.propertiesToMap(properties);
35 | assertEquals("my.value1", map.get("my.key1"));
36 | assertEquals("my.value2", map.get("my.key2"));
37 | assertEquals("2", map.get("my.key3"));
38 | }
39 |
40 | @Test
41 | void unableToConvertToString() {
42 | Properties properties = new Properties();
43 | properties.put("foo.bar", new UnconvertableString());
44 |
45 | Map map = ConfigSourceUtil.propertiesToMap(properties);
46 | assertTrue(map.isEmpty());
47 | }
48 |
49 | private static class UnconvertableString {
50 | @Override
51 | public String toString() {
52 | throw new UnsupportedOperationException();
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/examples/mapping/src/test/java/io/smallrye/config/examples/mapping/ServerMappingTest.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config.examples.mapping;
2 |
3 | import static java.util.stream.Collectors.toList;
4 | import static org.junit.jupiter.api.Assertions.assertEquals;
5 | import static org.junit.jupiter.api.Assertions.assertFalse;
6 | import static org.junit.jupiter.api.Assertions.assertTrue;
7 |
8 | import java.time.Duration;
9 | import java.util.stream.Stream;
10 |
11 | import org.junit.jupiter.api.Test;
12 |
13 | class ServerMappingTest {
14 | @Test
15 | void mapping() {
16 | final Server server = ServerMapping.getServer();
17 | assertEquals("localhost", server.host());
18 | assertEquals(8080, server.port());
19 | assertEquals(Duration.ofSeconds(60), server.timeout());
20 | assertEquals(200, server.threads());
21 |
22 | assertEquals("login.html", server.form().get("login-page"));
23 | assertEquals("error.html", server.form().get("error-page"));
24 | assertEquals("index.html", server.form().get("landing-page"));
25 |
26 | assertTrue(server.ssl().isPresent());
27 | assertEquals(8443, server.ssl().get().port());
28 | assertEquals(Stream.of("TLSv1.3", "TLSv1.2").collect(toList()), server.ssl().get().protocols());
29 |
30 | assertFalse(server.proxy().isPresent());
31 |
32 | assertFalse(server.log().enabled());
33 | assertEquals(".log", server.log().suffix());
34 | assertTrue(server.log().rotate());
35 | assertEquals(Server.Log.Pattern.COMMON, server.log().pattern());
36 |
37 | assertTrue(server.cors().isPresent());
38 | assertEquals("some-server", server.cors().get().origins().get(0).host());
39 | assertEquals(9000, server.cors().get().origins().get(0).port());
40 | assertEquals("another-server", server.cors().get().origins().get(1).host());
41 | assertEquals(8000, server.cors().get().origins().get(1).port());
42 | assertEquals("GET", server.cors().get().methods().get(0));
43 | assertEquals("POST", server.cors().get().methods().get(1));
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/sources/keystore/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 | smallrye-config-parent
6 | io.smallrye.config
7 | 3.15.1-SNAPSHOT
8 | ../../pom.xml
9 |
10 |
11 | smallrye-config-source-keystore
12 |
13 | SmallRye Config: ConfigSource - KeyStore
14 |
15 |
16 |
17 | io.smallrye.config
18 | smallrye-config
19 |
20 |
21 |
22 |
23 | org.junit.jupiter
24 | junit-jupiter
25 |
26 |
27 | io.smallrye.testing
28 | smallrye-testing-utilities
29 |
30 |
31 | jakarta.annotation
32 | jakarta.annotation-api
33 | test
34 |
35 |
36 |
37 |
38 |
39 |
40 | io.smallrye
41 | jandex-maven-plugin
42 | ${version.org.jboss.jandex}
43 |
44 |
45 | make-index
46 |
47 | jandex
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/implementation/src/main/java/io/smallrye/config/ConfigSourceInterceptorFactory.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config;
2 |
3 | import java.util.OptionalInt;
4 |
5 | /**
6 | * This ConfigSourceInterceptorFactory allows to initialize a {@link ConfigSourceInterceptor}, with access to the
7 | * current {@link ConfigSourceInterceptorContext}.
8 | *
9 | *
10 | * Interceptors in the chain are initialized in priority order and the current
11 | * {@link ConfigSourceInterceptorContext} contains the current interceptor, plus all other interceptors already
12 | * initialized.
13 | *
14 | *
15 | * Instances of this interface will be discovered by {@link SmallRyeConfigBuilder#addDiscoveredInterceptors()} via the
16 | * {@link java.util.ServiceLoader} mechanism and can be registered by providing a
17 | * {@code META-INF/services/io.smallrye.config.ConfigSourceInterceptorFactory} which contains the fully qualified class
18 | * name of the custom {@link ConfigSourceInterceptor} implementation.
19 | */
20 | public interface ConfigSourceInterceptorFactory {
21 | /**
22 | * The default priority value, {@link Priorities#APPLICATION}.
23 | */
24 | int DEFAULT_PRIORITY = Priorities.APPLICATION;
25 |
26 | /**
27 | * Gets the {@link ConfigSourceInterceptor} from the ConfigSourceInterceptorFactory. Implementations of this
28 | * method must provide the instance of the {@link ConfigSourceInterceptor} to add into the Config Interceptor Chain.
29 | *
30 | * @param context the current {@link ConfigSourceInterceptorContext} with the interceptors already initialized.
31 | * @return the {@link ConfigSourceInterceptor} to add to Config Interceptor Chain and initialize.
32 | */
33 | ConfigSourceInterceptor getInterceptor(final ConfigSourceInterceptorContext context);
34 |
35 | /**
36 | * Returns the interceptor priority. This is required, because the interceptor priority needs to be sorted
37 | * before doing initialization.
38 | *
39 | * @return the priority value.
40 | */
41 | default OptionalInt getPriority() {
42 | return OptionalInt.empty();
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/implementation/src/main/java/io/smallrye/config/WithKeys.java:
--------------------------------------------------------------------------------
1 | package io.smallrye.config;
2 |
3 | import java.lang.annotation.Documented;
4 | import java.lang.annotation.ElementType;
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 | import java.lang.annotation.Target;
8 | import java.util.function.Supplier;
9 |
10 | /**
11 | * Provide a list of map keys when populating {@link java.util.Map} types.
12 | *
13 | * When populating a {@link java.util.Map}, {@link SmallRyeConfig} requires the configuration names listed in
14 | * {@link SmallRyeConfig#getPropertyNames()} to be able to find the {@link java.util.Map} keys. The provided list will
15 | * effectively substitute the lookup in {@link SmallRyeConfig#getPropertyNames()}, thus enabling a
16 | * {@link org.eclipse.microprofile.config.spi.ConfigSource} that does not list its properties, to contribute
17 | * configuration to the {@link java.util.Map}.
18 | *
19 | * Each key must exist in the final configuration (relative to the {@link java.util.Map} path segment), or the mapping
20 | * will fail with a {@link ConfigValidationException}.
21 | *
22 | * In the case of {@link java.util.Map} value references a {@link java.util.Collection}, {@link SmallRyeConfig} would
23 | * still require the lookup in {@link SmallRyeConfig#getPropertyNames()}.
24 | */
25 | @Documented
26 | @Retention(RetentionPolicy.RUNTIME)
27 | @Target({ ElementType.METHOD, ElementType.TYPE_USE })
28 | public @interface WithKeys {
29 | /**
30 | * A {@link Class} implementing a {@link Supplier} of {@link Iterable} with the {@link java.util.Map} keys to look
31 | * in the configuration. Keys containing a dot are quoted.
32 | *