Skip to content

Commit

Permalink
Add a way to customize the SmallRyeConfigBuilder via ServiceLoader (#975
Browse files Browse the repository at this point in the history
)
  • Loading branch information
radcortez authored Aug 8, 2023
1 parent e18d3fd commit a80ebf0
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
Expand Down Expand Up @@ -643,6 +644,14 @@ public SmallRyeConfigBuilder setAddDiscoveredValidator(final boolean addDiscover
public SmallRyeConfig build() {
ConfigMappingProvider mappingProvider = mappingsBuilder.build();
defaultValues.putAll(mappingProvider.getDefaultValues());

ServiceLoader<SmallRyeConfigBuilderCustomizer> customizers = ServiceLoader.load(SmallRyeConfigBuilderCustomizer.class,
classLoader);
customizers.stream()
.map(ServiceLoader.Provider::get)
.sorted(Comparator.comparingInt(SmallRyeConfigBuilderCustomizer::priority))
.forEach(customizer -> customizer.configBuilder(SmallRyeConfigBuilder.this));

SmallRyeConfig config = new SmallRyeConfig(this);
ConfigMappings.mapConfiguration(config, mappingProvider);
return config;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.smallrye.config;

/**
* This {@code SmallRyeConfigBuilderCustomizer} allows to customize a {@link SmallRyeConfigBuilder}, used to create
* a {@link SmallRyeConfig} instance.
* <p>
* Instances of this interface will be discovered via the {@link java.util.ServiceLoader} mechanism and can be
* registered by providing a {@code META-INF/services/io.smallrye.config.SmallRyeConfigBuilderCustomizer} which
* contains the fully qualified class name of the custom {@link SmallRyeConfigBuilderCustomizer} implementation.
*/
public interface SmallRyeConfigBuilderCustomizer {
/**
* Customize the current {@link SmallRyeConfigBuilder}.
*
* @param builder the current {@link SmallRyeConfigBuilder}.
*/
void configBuilder(SmallRyeConfigBuilder builder);

/**
* Returns the customizer priority. Customizers are sorted by ascending priority and executed in that order.
*
* @return the priority value.
*/
default int priority() {
return 0;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package io.smallrye.config.test.builder;

import io.smallrye.config.SmallRyeConfigBuilder;
import io.smallrye.config.SmallRyeConfigBuilderCustomizer;

public class CustomConfigBuilder implements SmallRyeConfigBuilderCustomizer {
@Override
public void configBuilder(final SmallRyeConfigBuilder builder) {
builder.withDefaultValue("from.custom.builder", "1234");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package io.smallrye.config.test.builder;

import io.smallrye.config.SmallRyeConfigBuilder;
import io.smallrye.config.SmallRyeConfigBuilderCustomizer;

public class CustomOneConfigBuilder implements SmallRyeConfigBuilderCustomizer {
@Override
public void configBuilder(final SmallRyeConfigBuilder builder) {
builder.withDefaultValue("one", "one").addDefaultSources();
}

@Override
public int priority() {
return 1;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package io.smallrye.config.test.builder;

import io.smallrye.config.SmallRyeConfigBuilder;
import io.smallrye.config.SmallRyeConfigBuilderCustomizer;

public class CustomTwoConfigBuilder implements SmallRyeConfigBuilderCustomizer {
@Override
public void configBuilder(final SmallRyeConfigBuilder builder) {
builder.withDefaultValue("one", "two");
if (builder.isAddDefaultSources()) {
builder.withDefaultValue("addDefaultSources", "true");
}
}

@Override
public int priority() {
return 2;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package io.smallrye.config.test.builder;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Path;
import java.util.stream.Stream;

import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.jboss.shrinkwrap.api.exporter.ZipExporter;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;

import io.smallrye.config.SmallRyeConfig;
import io.smallrye.config.SmallRyeConfigBuilder;

public class SmallRyeConfigBuilderCustomizerTest {
@Test
void builder(@TempDir Path tempDir) throws Exception {
JavaArchive serviceJar = ShrinkWrap
.create(JavaArchive.class, "service.jar")
.addAsManifestResource(new StringAsset("io.smallrye.config.test.builder.CustomConfigBuilder"),
"services/io.smallrye.config.SmallRyeConfigBuilderCustomizer");

Path servidePath = tempDir.resolve("resources-one.jar");
serviceJar.as(ZipExporter.class).exportTo(servidePath.toFile());

ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();

try (URLClassLoader urlClassLoader = urlClassLoader(contextClassLoader, "jar:" + servidePath.toUri() + "!/")) {
Thread.currentThread().setContextClassLoader(urlClassLoader);

SmallRyeConfig config = new SmallRyeConfigBuilder().build();

assertEquals("1234", config.getRawValue("from.custom.builder"));
} finally {
Thread.currentThread().setContextClassLoader(contextClassLoader);
}
}

@Test
void priority(@TempDir Path tempDir) throws Exception {
JavaArchive serviceJar = ShrinkWrap
.create(JavaArchive.class, "service.jar")
.addAsManifestResource(new StringAsset(
"io.smallrye.config.test.builder.CustomOneConfigBuilder\n" +
"io.smallrye.config.test.builder.CustomTwoConfigBuilder\n"),
"services/io.smallrye.config.SmallRyeConfigBuilderCustomizer");

Path servidePath = tempDir.resolve("resources-one.jar");
serviceJar.as(ZipExporter.class).exportTo(servidePath.toFile());

ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();

try (URLClassLoader urlClassLoader = urlClassLoader(contextClassLoader, "jar:" + servidePath.toUri() + "!/")) {
Thread.currentThread().setContextClassLoader(urlClassLoader);

SmallRyeConfig config = new SmallRyeConfigBuilder().build();

assertEquals("two", config.getRawValue("one"));
assertEquals("true", config.getRawValue("addDefaultSources"));
} finally {
Thread.currentThread().setContextClassLoader(contextClassLoader);
}
}

private static URLClassLoader urlClassLoader(ClassLoader parent, String... urls) {
return new URLClassLoader(Stream.of(urls).map(spec -> {
try {
return new URL(spec);
} catch (MalformedURLException e) {
throw new IllegalArgumentException(e);
}
}).toArray(URL[]::new), parent);
}
}

0 comments on commit a80ebf0

Please sign in to comment.