Skip to content

Commit

Permalink
Fallback to the old Env name matching when case-sensitive env name ma…
Browse files Browse the repository at this point in the history
…tching does not return results (smallrye#1051)
  • Loading branch information
radcortez authored Nov 10, 2023
1 parent ffcad09 commit 5a96de2
Show file tree
Hide file tree
Showing 2 changed files with 157 additions and 41 deletions.
138 changes: 115 additions & 23 deletions implementation/src/main/java/io/smallrye/config/EnvConfigSource.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@

import static io.smallrye.config.common.utils.ConfigSourceUtil.CONFIG_ORDINAL_KEY;
import static io.smallrye.config.common.utils.StringUtil.isNumeric;
import static io.smallrye.config.common.utils.StringUtil.replaceNonAlphanumericByUnderscores;
import static io.smallrye.config.common.utils.StringUtil.toLowerCaseAndDotted;
import static java.lang.Character.toLowerCase;
import static java.security.AccessController.doPrivileged;

import java.io.Serializable;
Expand All @@ -27,7 +30,6 @@
import java.util.Set;

import io.smallrye.config.common.AbstractConfigSource;
import io.smallrye.config.common.utils.StringUtil;

/**
* A {@link org.eclipse.microprofile.config.spi.ConfigSource} to access Environment Variables following the mapping
Expand Down Expand Up @@ -59,8 +61,7 @@ public class EnvConfigSource extends AbstractConfigSource {

private static final int DEFAULT_ORDINAL = 300;

private final Map<EnvProperty, String> properties;
private final Set<String> names;
private final EnvVars envVars;

protected EnvConfigSource() {
this(DEFAULT_ORDINAL);
Expand All @@ -72,38 +73,35 @@ protected EnvConfigSource(final int ordinal) {

public EnvConfigSource(final Map<String, String> properties, final int ordinal) {
super("EnvConfigSource", getEnvOrdinal(properties, ordinal));
this.properties = new HashMap<>(properties.size());
this.names = new HashSet<>(properties.size() * 2);
for (Map.Entry<String, String> entry : properties.entrySet()) {
this.properties.put(new EnvProperty(entry.getKey()), entry.getValue());
this.names.add(entry.getKey());
String keyLowerCaseAndDotted = StringUtil.toLowerCaseAndDotted(entry.getKey());
this.properties.putIfAbsent(new EnvProperty(keyLowerCaseAndDotted), entry.getValue());
this.names.add(keyLowerCaseAndDotted);
}
this.envVars = new EnvVars(properties);
}

@Override
public Map<String, String> getProperties() {
Map<String, String> properties = new HashMap<>(this.properties.size());
for (Map.Entry<EnvProperty, String> entry : this.properties.entrySet()) {
properties.put(entry.getKey().getName(), entry.getValue());
Map<String, String> properties = new HashMap<>();
for (Map.Entry<EnvName, EnvEntry> entry : envVars.getEnv().entrySet()) {
EnvEntry entryValue = entry.getValue();
if (entryValue.getEntries() != null) {
properties.putAll(entryValue.getEntries());
} else {
properties.put(entryValue.getName(), entryValue.getValue());
}
}
return properties;
}

@Override
public Set<String> getPropertyNames() {
return names;
return envVars.getNames();
}

@Override
public String getValue(final String propertyName) {
return this.properties.get(new EnvProperty(propertyName));
return envVars.get(propertyName);
}

boolean hasPropertyName(final String propertyName) {
return properties.containsKey(new EnvProperty(propertyName));
return envVars.getEnv().containsKey(new EnvName(propertyName));
}

/**
Expand Down Expand Up @@ -143,12 +141,67 @@ Object readResolve() {
}
}

static final class EnvProperty implements Serializable {
static final class EnvVars implements Serializable {
private static final long serialVersionUID = -56318356411229247L;

private final Map<EnvName, EnvEntry> env;
private final Set<String> names;

public EnvVars(final Map<String, String> properties) {
this.env = new HashMap<>(properties.size());
this.names = new HashSet<>(properties.size() * 2);
for (Map.Entry<String, String> entry : properties.entrySet()) {
EnvName envName = new EnvName(entry.getKey());
EnvEntry envEntry = env.get(envName);
if (envEntry == null) {
env.put(envName, new EnvEntry(entry.getKey(), entry.getValue()));
} else {
envEntry.add(entry.getKey(), entry.getValue());
}
this.names.add(entry.getKey());
this.names.add(toLowerCaseAndDotted(entry.getKey()));
}
}

public String get(final String propertyName) {
EnvEntry envEntry = env.get(new EnvName(propertyName));
if (envEntry != null) {
String value = envEntry.get();
if (value != null) {
return value;
}

value = envEntry.getEntries().get(propertyName);
if (value != null) {
return value;
}

String envName = replaceNonAlphanumericByUnderscores(propertyName);
value = envEntry.getEntries().get(envName);
if (value != null) {
return value;
}

return envEntry.envEntries.get(envName.toUpperCase());
}
return null;
}

public Map<EnvName, EnvEntry> getEnv() {
return env;
}

public Set<String> getNames() {
return names;
}
}

static final class EnvName implements Serializable {
private static final long serialVersionUID = -2679716955093904512L;

private final String name;

public EnvProperty(final String name) {
public EnvName(final String name) {
assert name != null;
this.name = name;
}
Expand All @@ -165,7 +218,7 @@ public boolean equals(final Object o) {
if (o == null || getClass() != o.getClass()) {
return false;
}
final EnvProperty that = (EnvProperty) o;
final EnvName that = (EnvName) o;
return equals(this.name, that.name);
}

Expand Down Expand Up @@ -199,7 +252,8 @@ public int hashCode() {
case '/':
continue;
}
h = 31 * h + c;
h = 31 * h + toLowerCase(c);
// h = 31 * h + c;
}
return h;
}
Expand Down Expand Up @@ -288,7 +342,8 @@ && isNumeric(name, matchPosition - range, matchPosition)) {
return false;
}
}
} else if (o != n) {
// } else if (o != n) {
} else if (toLowerCase(o) != toLowerCase(n)) {
return false;
}
matchPosition--;
Expand All @@ -297,4 +352,41 @@ && isNumeric(name, matchPosition - range, matchPosition)) {
return matchPosition <= 0;
}
}

static final class EnvEntry implements Serializable {
private static final long serialVersionUID = -8786927401082731020L;

private final String name;
private final String value;
private Map<String, String> envEntries;

EnvEntry(final String name, final String value) {
this.name = name;
this.value = value;
}

String getName() {
return name;
}

String getValue() {
return value;
}

String get() {
return envEntries == null ? value : null;
}

Map<String, String> getEntries() {
return envEntries;
}

void add(String name, String value) {
if (envEntries == null) {
envEntries = new HashMap<>();
envEntries.put(this.name, this.value);
}
envEntries.put(name, value);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
import org.eclipse.microprofile.config.spi.ConfigSource;
import org.junit.jupiter.api.Test;

import io.smallrye.config.EnvConfigSource.EnvProperty;
import io.smallrye.config.EnvConfigSource.EnvName;

/**
* @author <a href="http://jmesnil.net/">Jeff Mesnil</a> (c) 2018 Red Hat inc.
Expand Down Expand Up @@ -166,33 +166,49 @@ void map() {

@Test
void envEquals() {
assertTrue(EnvProperty.equals("", new String("")));
assertTrue(EnvProperty.equals(" ", new String(" ")));
assertFalse(EnvProperty.equals(" ", new String("foo.bar")));
assertFalse(EnvProperty.equals(" ", new String("FOO_BAR")));
assertFalse(EnvProperty.equals("foo.bar", new String("")));
assertFalse(EnvProperty.equals("FOO_BAR", new String("")));
assertTrue(EnvName.equals("", new String("")));
assertTrue(EnvName.equals(" ", new String(" ")));
assertFalse(EnvName.equals(" ", new String("foo.bar")));
assertFalse(EnvName.equals(" ", new String("FOO_BAR")));
assertFalse(EnvName.equals("foo.bar", new String("")));
assertFalse(EnvName.equals("FOO_BAR", new String("")));

assertFalse(EnvProperty.equals("BAR", new String("foo.bar")));
assertFalse(EnvProperty.equals("foo.bar", new String("BAR")));
assertFalse(EnvName.equals("BAR", new String("foo.bar")));
assertFalse(EnvName.equals("foo.bar", new String("BAR")));

assertTrue(envSourceEquals("FOO_BAR", new String("FOO_BAR")));
assertTrue(envSourceEquals("FOO_BAR", new String("foo.bar")));
assertTrue(envSourceEquals("FOO_BAR", new String("FOO.BAR")));
assertTrue(envSourceEquals("FOO_BAR", new String("foo-bar")));
assertTrue(envSourceEquals("FOO_BAR", new String("foo_bar")));

assertTrue(EnvProperty.equals("foo.bar", new String("foo.bar")));
assertTrue(EnvProperty.equals("foo-bar", new String("foo-bar")));
assertTrue(EnvProperty.equals("FOO.BAR", new String("FOO_BAR")));
assertTrue(EnvName.equals("foo.bar", new String("foo.bar")));
assertTrue(EnvName.equals("foo-bar", new String("foo-bar")));
assertTrue(EnvName.equals("foo.bar", new String("FOO_BAR")));
assertTrue(EnvName.equals("FOO.BAR", new String("FOO_BAR")));
assertTrue(EnvName.equals("foo-bar", new String("FOO_BAR")));
assertTrue(EnvName.equals("foo_bar", new String("FOO_BAR")));

assertTrue(EnvName.equals("FOO__BAR__BAZ", new String("foo.\"bar\".baz")));
assertTrue(EnvName.equals("foo.\"bar\".baz", new String("FOO__BAR__BAZ")));
assertTrue(envSourceEquals("FOO__BAR__BAZ", new String("foo.\"bar\".baz")));
assertTrue(EnvName.equals("FOO__BAR__BAZ_0__Z_0_", new String("foo.\"bar\".baz[0].z[0]")));
assertTrue(envSourceEquals("FOO__BAR__BAZ_0__Z_0_", new String("foo.\"bar\".baz[0].z[0]")));

assertTrue(EnvName.equals("_DEV_FOO_BAR", new String("%dev.foo.bar")));
assertTrue(EnvName.equals("%dev.foo.bar", new String("_DEV_FOO_BAR")));
assertTrue(envSourceEquals("_DEV_FOO_BAR", new String("%dev.foo.bar")));
assertTrue(EnvName.equals("_ENV_SMALLRYE_MP_CONFIG_PROP", new String("_ENV_SMALLRYE_MP_CONFIG_PROP")));
assertTrue(EnvName.equals("%env.smallrye.mp.config.prop", new String("%env.smallrye.mp.config.prop")));
assertTrue(EnvName.equals("_ENV_SMALLRYE_MP_CONFIG_PROP", new String("%env.smallrye.mp.config.prop")));
assertTrue(EnvName.equals("%env.smallrye.mp.config.prop", new String("_ENV_SMALLRYE_MP_CONFIG_PROP")));
assertTrue(envSourceEquals("%env.smallrye.mp.config.prop", new String("%env.smallrye.mp.config.prop")));
assertTrue(envSourceEquals("_ENV_SMALLRYE_MP_CONFIG_PROP", new String("%env.smallrye.mp.config.prop")));

assertTrue(EnvName.equals("indexed[0]", new String("indexed[0]")));
assertTrue(EnvName.equals("INDEXED_0_", new String("INDEXED_0_")));
assertTrue(EnvName.equals("indexed[0]", new String("INDEXED_0_")));
assertTrue(EnvName.equals("INDEXED_0_", new String("indexed[0]")));
assertTrue(envSourceEquals("indexed[0]", new String("indexed[0]")));
assertTrue(envSourceEquals("INDEXED_0_", new String("INDEXED_0_")));
assertTrue(envSourceEquals("INDEXED_0_", new String("indexed[0]")));
Expand All @@ -201,14 +217,22 @@ void envEquals() {
assertTrue(envSourceEquals("foo.bar[0].indexed[0]", new String("foo.bar[0].indexed[0]")));
assertTrue(envSourceEquals("FOO_BAR_0__INDEXED_0_", new String("foo.bar[0].indexed[0]")));

assertTrue(EnvName.equals("env.\"quoted.key\".value", new String("env.\"quoted.key\".value")));
assertTrue(EnvName.equals("ENV__QUOTED_KEY__VALUE", new String("ENV__QUOTED_KEY__VALUE")));
assertTrue(EnvName.equals("ENV__QUOTED_KEY__VALUE", new String("env.\"quoted.key\".value")));
assertTrue(EnvName.equals("env.\"quoted.key\".value", new String("ENV__QUOTED_KEY__VALUE")));
assertTrue(EnvName.equals("env.\"quoted.key\".value", new String("env.\"quoted-key\".value")));
assertTrue(EnvName.equals("env.\"quoted-key\".value", new String("env.\"quoted.key\".value")));
assertTrue(envSourceEquals("env.\"quoted.key\".value", new String("env.\"quoted.key\".value")));
assertTrue(envSourceEquals("ENV__QUOTED_KEY__VALUE", new String("ENV__QUOTED_KEY__VALUE")));
assertTrue(envSourceEquals("ENV__QUOTED_KEY__VALUE", new String("env.\"quoted.key\".value")));
assertTrue(envSourceEquals("env.\"quoted.key\".value", new String("env.\"quoted-key\".value")));
assertTrue(envSourceEquals("env.\"quoted-key\".value", new String("env.\"quoted.key\".value")));
assertTrue(envSourceEquals("TEST_LANGUAGE__DE_ETR__", new String("test.language.\"de.etr\"")));

assertTrue(EnvProperty.equals("smallrye/mp/config/prop", new String("smallrye/mp/config/prop")));
assertTrue(EnvName.equals("TEST_LANGUAGE__DE_ETR__", new String("test.language.\"de.etr\"")));
assertTrue(EnvName.equals("test.language.\"de.etr\"", new String("TEST_LANGUAGE__DE_ETR__")));
assertEquals(new EnvName("TEST_LANGUAGE__DE_ETR_").hashCode(), new EnvName("test.language.\"de.etr\"").hashCode());

assertTrue(envSourceEquals("SMALLRYE_MP_CONFIG_PROP", new String("smallrye/mp/config/prop")));
}

Expand All @@ -229,12 +253,12 @@ void sameSemanticMeaning() {

@Test
void sameNames() {
assertTrue(envSourceEquals("FOOBAR", "foobar"));
assertTrue(envSourceEquals("FOOBAR", "fooBar"));

EnvConfigSource envConfigSource = new EnvConfigSource(
Map.of("my_string_property", "lower", "MY_STRING_PROPERTY", "upper"), 100);
assertFalse(EnvProperty.equals("MY_STRING_PROPERTY", "my_string_property"));
assertFalse(EnvProperty.equals("my_string_property", "MY_STRING_PROPERTY"));
assertTrue(EnvProperty.equals("my_string_property", "my_string_property"));
assertTrue(EnvProperty.equals("MY_STRING_PROPERTY", "MY_STRING_PROPERTY"));
assertEquals(2, envConfigSource.getProperties().size());
assertEquals("lower", envConfigSource.getValue("my_string_property"));
assertEquals("upper", envConfigSource.getValue("MY_STRING_PROPERTY"));
}
Expand Down

0 comments on commit 5a96de2

Please sign in to comment.