Skip to content

Commit

Permalink
Match most specific mapping prefix when matching environment variables
Browse files Browse the repository at this point in the history
  • Loading branch information
radcortez committed Dec 11, 2024
1 parent 95881f0 commit ac93b31
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
Expand Down Expand Up @@ -70,7 +71,11 @@ public Map<String, Map<String, Set<String>>> get() {

this.config = config;
this.names = new ConfigMappingNames(names);
matchPropertiesWithEnv(roots);
Set<String> mappingsPrefixes = new HashSet<>();
for (Set<String> mappingPrefixes : roots.values()) {
mappingsPrefixes.addAll(mappingPrefixes);
}
matchPropertiesWithEnv(mappingsPrefixes);
for (Map.Entry<Class<?>, Set<String>> mapping : roots.entrySet()) {
Map<String, ConfigMappingObject> mappingObjects = new HashMap<>();
for (String rootPath : mapping.getValue()) {
Expand Down Expand Up @@ -172,19 +177,36 @@ Map<Class<?>, Map<String, ConfigMappingObject>> getRootsMap() {
return roots;
}

private void matchPropertiesWithEnv(final Map<Class<?>, Set<String>> roots) {
private void matchPropertiesWithEnv(final Set<String> mappingsPrefixes) {
// TODO - We shouldn't be mutating the EnvSource.
// We should do the calculation when creating the EnvSource, but right now mappings and sources are not well integrated.

Set<String> rootPaths = new HashSet<>();
for (Set<String> paths : roots.values()) {
rootPaths.addAll(paths);
}
boolean all = rootPaths.contains("");
List<String> prefixes = new ArrayList<>(mappingsPrefixes);
// Sort by number of segments to match the most specific ones first
prefixes.sort(new Comparator<String>() {
@Override
public int compare(final String o1, final String o2) {
int segmentsO1 = 0;
for (int i = 0; i < o1.length(); i++) {
if (o1.charAt(i) == '.') {
segmentsO1++;
}
}

int segmentsO2 = 0;
for (int i = 0; i < o2.length(); i++) {
if (o2.charAt(i) == '.') {
segmentsO2++;
}
}
return Integer.compare(segmentsO2, segmentsO1);
}
});
boolean all = prefixes.contains("");
StringBuilder sb = new StringBuilder();

for (ConfigSource configSource : config.getConfigSources(EnvConfigSource.class)) {
if (roots.isEmpty()) {
if (prefixes.isEmpty()) {
break;
}

Expand All @@ -201,7 +223,7 @@ private void matchPropertiesWithEnv(final Map<Class<?>, Set<String>> roots) {

String matchedRoot = null;
if (!all) {
for (String rootPath : rootPaths) {
for (String rootPath : prefixes) {
if (StringUtil.isInPath(rootPath, activeEnvProperty)) {
matchedRoot = rootPath;
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,86 @@ interface ServiceDiscoveryConfiguration {
}
}

@Test
void mappingMapsWithEnvMultiplePrefixes() {
SmallRyeConfig config = new SmallRyeConfigBuilder()
.withSources(new EnvConfigSource(Map.of(
"PREFIX_COMPOSED_SERVICE_SERVICE_DISCOVERY_ADDRESS", "from-env"), 300))
.withMapping(SimplePrefix.class)
.withMapping(ComposedPrefix.class)
.build();

ComposedPrefix mapping = config.getConfigMapping(ComposedPrefix.class);
assertEquals("from-env", mapping.serviceConfiguration().get("service").serviceDiscovery().params().get("address"));
}

@ConfigMapping(prefix = "prefix")
interface SimplePrefix {
Optional<String> value();
}

@ConfigMapping(prefix = "prefix.composed")
interface ComposedPrefix {
@WithParentName
Map<String, ServiceConfiguration> serviceConfiguration();

interface ServiceConfiguration {
ServiceDiscoveryConfiguration serviceDiscovery();

interface ServiceDiscoveryConfiguration {
@WithParentName
Map<String, String> params();
}
}
}

@Test
void mappingsMapsWithEnvSplit() {
SmallRyeConfig config = new SmallRyeConfigBuilder()
.withSources(new EnvConfigSource(Map.of(
"SERVICES_SERVICE_SERVICE_DISCOVERY_ADDRESS", "from-env",
"SERVICES_SERVICE_ANOTHER_DISCOVERY_ADDRESS", "from-env"), 300))
.withMapping(ServicesOne.class)
.withMapping(ServicesTwo.class)
.build();

ServicesOne servicesOne = config.getConfigMapping(ServicesOne.class);
ServicesTwo servicesTwo = config.getConfigMapping(ServicesTwo.class);

assertEquals("from-env", servicesOne.serviceConfiguration().get("service").serviceDiscovery().params().get("address"));
assertEquals("from-env", servicesTwo.serviceConfiguration().get("service").anotherDiscovery().params().get("address"));
}

@ConfigMapping(prefix = "services")
interface ServicesOne {
@WithParentName
Map<String, ServiceConfiguration> serviceConfiguration();

interface ServiceConfiguration {
ServiceDiscoveryConfiguration serviceDiscovery();

interface ServiceDiscoveryConfiguration {
@WithParentName
Map<String, String> params();
}
}
}

@ConfigMapping(prefix = "services")
interface ServicesTwo {
@WithParentName
Map<String, ServiceConfiguration> serviceConfiguration();

interface ServiceConfiguration {
ServiceDiscoveryConfiguration anotherDiscovery();

interface ServiceDiscoveryConfiguration {
@WithParentName
Map<String, String> params();
}
}
}

private static boolean envSourceEquals(String name, String lookup) {
return BOOLEAN_CONVERTER.convert(new EnvConfigSource(Map.of(name, "true"), 100).getValue(lookup));
}
Expand Down

0 comments on commit ac93b31

Please sign in to comment.