Browse Source
Rename classes to align with existing `SystemEnvironment...` classes and extract common `FileExtensionHint` logic. See gh-41609pull/44044/head
14 changed files with 455 additions and 305 deletions
@ -1,58 +0,0 @@
@@ -1,58 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2025 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.boot.context.config; |
||||
|
||||
import java.io.IOException; |
||||
import java.nio.charset.StandardCharsets; |
||||
import java.util.function.Function; |
||||
|
||||
import org.springframework.core.io.ByteArrayResource; |
||||
|
||||
/** |
||||
* {@link ConfigDataLoader} to load data from environment variables. |
||||
* |
||||
* @author Moritz Halbritter |
||||
*/ |
||||
class EnvConfigDataLoader implements ConfigDataLoader<EnvConfigDataResource> { |
||||
|
||||
private final Function<String, String> readEnvVariable; |
||||
|
||||
EnvConfigDataLoader() { |
||||
this.readEnvVariable = System::getenv; |
||||
} |
||||
|
||||
EnvConfigDataLoader(Function<String, String> readEnvVariable) { |
||||
this.readEnvVariable = readEnvVariable; |
||||
} |
||||
|
||||
@Override |
||||
public ConfigData load(ConfigDataLoaderContext context, EnvConfigDataResource resource) |
||||
throws IOException, ConfigDataResourceNotFoundException { |
||||
String content = this.readEnvVariable.apply(resource.getVariableName()); |
||||
if (content == null) { |
||||
throw new ConfigDataResourceNotFoundException(resource); |
||||
} |
||||
String name = String.format("Environment variable '%s' via location '%s'", resource.getVariableName(), |
||||
resource.getLocation()); |
||||
return new ConfigData(resource.getLoader().load(name, createResource(content))); |
||||
} |
||||
|
||||
private ByteArrayResource createResource(String content) { |
||||
return new ByteArrayResource(content.getBytes(StandardCharsets.UTF_8)); |
||||
} |
||||
|
||||
} |
||||
@ -1,75 +0,0 @@
@@ -1,75 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2025 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.boot.context.config; |
||||
|
||||
import java.util.Objects; |
||||
|
||||
import org.springframework.boot.env.PropertySourceLoader; |
||||
|
||||
/** |
||||
* {@link ConfigDataResource} used by {@link EnvConfigDataLoader}. |
||||
* |
||||
* @author Moritz Halbritter |
||||
*/ |
||||
class EnvConfigDataResource extends ConfigDataResource { |
||||
|
||||
private final ConfigDataLocation location; |
||||
|
||||
private final String variableName; |
||||
|
||||
private final PropertySourceLoader loader; |
||||
|
||||
EnvConfigDataResource(ConfigDataLocation location, String variableName, PropertySourceLoader loader) { |
||||
super(location.isOptional()); |
||||
this.location = location; |
||||
this.variableName = variableName; |
||||
this.loader = loader; |
||||
} |
||||
|
||||
ConfigDataLocation getLocation() { |
||||
return this.location; |
||||
} |
||||
|
||||
String getVariableName() { |
||||
return this.variableName; |
||||
} |
||||
|
||||
PropertySourceLoader getLoader() { |
||||
return this.loader; |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object o) { |
||||
if (o == null || getClass() != o.getClass()) { |
||||
return false; |
||||
} |
||||
EnvConfigDataResource that = (EnvConfigDataResource) o; |
||||
return Objects.equals(this.location, that.location) && Objects.equals(this.variableName, that.variableName) |
||||
&& Objects.equals(this.loader, that.loader); |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
return Objects.hash(this.location, this.variableName, this.loader); |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return "env variable [" + this.variableName + "]"; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,82 @@
@@ -0,0 +1,82 @@
|
||||
/* |
||||
* Copyright 2012-2025 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.boot.context.config; |
||||
|
||||
import java.util.regex.Matcher; |
||||
import java.util.regex.Pattern; |
||||
|
||||
/** |
||||
* User provided hint for an otherwise missing file extension. |
||||
* |
||||
* @author Phillip Webb |
||||
*/ |
||||
final class FileExtensionHint { |
||||
|
||||
private static final Pattern PATTERN = Pattern.compile("^(.*)\\[(\\.\\w+)](?!\\[)$"); |
||||
|
||||
private static final FileExtensionHint NONE = new FileExtensionHint(null); |
||||
|
||||
private final Matcher matcher; |
||||
|
||||
private FileExtensionHint(Matcher matcher) { |
||||
this.matcher = matcher; |
||||
} |
||||
|
||||
/** |
||||
* Return {@code true} if the hint is present. |
||||
* @return if the hint is present |
||||
*/ |
||||
boolean isPresent() { |
||||
return this.matcher != null; |
||||
} |
||||
|
||||
/** |
||||
* Return the extension from the hint or return the parameter if the hint is not |
||||
* {@link #isPresent() present}. |
||||
* @param extension the fallback extension |
||||
* @return the extension either from the hint or fallback |
||||
*/ |
||||
String orElse(String extension) { |
||||
return (this.matcher != null) ? toString() : extension; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return (this.matcher != null) ? this.matcher.group(2) : ""; |
||||
} |
||||
|
||||
/** |
||||
* Return the {@link FileExtensionHint} from the given value. |
||||
* @param value the source value |
||||
* @return the {@link FileExtensionHint} (never {@code null}) |
||||
*/ |
||||
static FileExtensionHint from(String value) { |
||||
Matcher matcher = PATTERN.matcher(value); |
||||
return (matcher.matches()) ? new FileExtensionHint(matcher) : NONE; |
||||
} |
||||
|
||||
/** |
||||
* Remove any hint from the given value. |
||||
* @param value the source value |
||||
* @return the value without any hint |
||||
*/ |
||||
static String removeFrom(String value) { |
||||
Matcher matcher = PATTERN.matcher(value); |
||||
return (matcher.matches()) ? matcher.group(1) : value; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,41 @@
@@ -0,0 +1,41 @@
|
||||
/* |
||||
* Copyright 2012-2025 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.boot.context.config; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.List; |
||||
|
||||
import org.springframework.core.env.PropertySource; |
||||
|
||||
/** |
||||
* {@link ConfigDataLoader} to load data from system environment variables. |
||||
* |
||||
* @author Moritz Halbritter |
||||
*/ |
||||
class SystemEnvironmentConfigDataLoader implements ConfigDataLoader<SystemEnvironmentConfigDataResource> { |
||||
|
||||
@Override |
||||
public ConfigData load(ConfigDataLoaderContext context, SystemEnvironmentConfigDataResource resource) |
||||
throws IOException, ConfigDataResourceNotFoundException { |
||||
List<PropertySource<?>> loaded = resource.load(); |
||||
if (loaded == null) { |
||||
throw new ConfigDataResourceNotFoundException(resource); |
||||
} |
||||
return new ConfigData(loaded); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,92 @@
@@ -0,0 +1,92 @@
|
||||
/* |
||||
* Copyright 2012-2025 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.boot.context.config; |
||||
|
||||
import java.io.IOException; |
||||
import java.nio.charset.StandardCharsets; |
||||
import java.util.List; |
||||
import java.util.Objects; |
||||
import java.util.function.Function; |
||||
|
||||
import org.springframework.boot.env.PropertySourceLoader; |
||||
import org.springframework.core.env.PropertySource; |
||||
import org.springframework.core.io.ByteArrayResource; |
||||
import org.springframework.util.ClassUtils; |
||||
import org.springframework.util.StringUtils; |
||||
|
||||
/** |
||||
* {@link ConfigDataResource} used by {@link SystemEnvironmentConfigDataLoader}. |
||||
* |
||||
* @author Moritz Halbritter |
||||
*/ |
||||
class SystemEnvironmentConfigDataResource extends ConfigDataResource { |
||||
|
||||
private final String variableName; |
||||
|
||||
private final PropertySourceLoader loader; |
||||
|
||||
private final Function<String, String> environment; |
||||
|
||||
SystemEnvironmentConfigDataResource(String variableName, PropertySourceLoader loader, |
||||
Function<String, String> environment) { |
||||
this.variableName = variableName; |
||||
this.loader = loader; |
||||
this.environment = environment; |
||||
} |
||||
|
||||
String getVariableName() { |
||||
return this.variableName; |
||||
} |
||||
|
||||
PropertySourceLoader getLoader() { |
||||
return this.loader; |
||||
} |
||||
|
||||
List<PropertySource<?>> load() throws IOException { |
||||
String content = this.environment.apply(this.variableName); |
||||
return (content != null) ? this.loader.load(StringUtils.capitalize(toString()), asResource(content)) : null; |
||||
} |
||||
|
||||
private ByteArrayResource asResource(String content) { |
||||
return new ByteArrayResource(content.getBytes(StandardCharsets.UTF_8)); |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object obj) { |
||||
if (this == obj) { |
||||
return true; |
||||
} |
||||
if (obj == null || getClass() != obj.getClass()) { |
||||
return false; |
||||
} |
||||
SystemEnvironmentConfigDataResource other = (SystemEnvironmentConfigDataResource) obj; |
||||
return Objects.equals(this.loader.getClass(), other.loader.getClass()) |
||||
&& Objects.equals(this.variableName, other.variableName); |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
return Objects.hash(this.variableName, this.loader.getClass()); |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return "system envionement variable [" + this.variableName + "] content loaded using " |
||||
+ ClassUtils.getShortName(this.loader.getClass()); |
||||
} |
||||
|
||||
} |
||||
@ -1,65 +0,0 @@
@@ -1,65 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2025 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.boot.context.config; |
||||
|
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.boot.env.PropertiesPropertySourceLoader; |
||||
import org.springframework.boot.env.PropertySourceLoader; |
||||
import org.springframework.boot.env.YamlPropertySourceLoader; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Tests for {@link EnvConfigDataResource}. |
||||
* |
||||
* @author Moritz Halbritter |
||||
*/ |
||||
class EnvConfigDataResourceTests { |
||||
|
||||
private final YamlPropertySourceLoader yamlPropertySourceLoader = new YamlPropertySourceLoader(); |
||||
|
||||
private final PropertiesPropertySourceLoader propertiesPropertySourceLoader = new PropertiesPropertySourceLoader(); |
||||
|
||||
@Test |
||||
void shouldHaveEqualsAndHashcode() { |
||||
EnvConfigDataResource var1 = createResource("VAR1"); |
||||
EnvConfigDataResource var2 = createResource("VAR2"); |
||||
EnvConfigDataResource var3 = createResource("VAR1", this.yamlPropertySourceLoader); |
||||
EnvConfigDataResource var4 = createResource("VAR1"); |
||||
assertThat(var1).isNotEqualTo(var2); |
||||
assertThat(var1).isNotEqualTo(var3); |
||||
assertThat(var1).isEqualTo(var4); |
||||
assertThat(var1).hasSameHashCodeAs(var4); |
||||
} |
||||
|
||||
@Test |
||||
void shouldHaveToString() { |
||||
EnvConfigDataResource resource = createResource("VAR1"); |
||||
assertThat(resource).hasToString("env variable [VAR1]"); |
||||
} |
||||
|
||||
private EnvConfigDataResource createResource(String variableName) { |
||||
return createResource(variableName, this.propertiesPropertySourceLoader); |
||||
} |
||||
|
||||
private EnvConfigDataResource createResource(String variableName, PropertySourceLoader propertySourceLoader) { |
||||
return new EnvConfigDataResource(ConfigDataLocation.of("env:" + variableName), variableName, |
||||
propertySourceLoader); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,72 @@
@@ -0,0 +1,72 @@
|
||||
/* |
||||
* Copyright 2012-2025 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.boot.context.config; |
||||
|
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Tests for {@link FileExtensionHint}. |
||||
* |
||||
* @author Phillip Webb |
||||
*/ |
||||
class FileExtensionHintTests { |
||||
|
||||
@Test |
||||
void isPresentWhenHasHint() { |
||||
assertThat(FileExtensionHint.from("foo[.bar]").isPresent()).isTrue(); |
||||
} |
||||
|
||||
@Test |
||||
void isPresentWhenHasNoHint() { |
||||
assertThat(FileExtensionHint.from("foo").isPresent()).isFalse(); |
||||
assertThat(FileExtensionHint.from("foo[bar]").isPresent()).isFalse(); |
||||
assertThat(FileExtensionHint.from("foo[.b[ar]").isPresent()).isFalse(); |
||||
} |
||||
|
||||
@Test |
||||
void orElseWhenHasHint() { |
||||
assertThat(FileExtensionHint.from("foo[.bar]").orElse(".txt")).isEqualTo(".bar"); |
||||
} |
||||
|
||||
@Test |
||||
void orElseWhenHasNoHint() { |
||||
assertThat(FileExtensionHint.from("foo").orElse(".txt")).isEqualTo(".txt"); |
||||
} |
||||
|
||||
@Test |
||||
void toStringWhenHasHintReturnsDotExtension() { |
||||
assertThat(FileExtensionHint.from("foo[.bar]")).hasToString(".bar"); |
||||
} |
||||
|
||||
@Test |
||||
void toStringWhenHasNoHintReturnsEmpty() { |
||||
assertThat(FileExtensionHint.from("foo")).hasToString(""); |
||||
} |
||||
|
||||
@Test |
||||
void removeFromWhenHasHint() { |
||||
assertThat(FileExtensionHint.removeFrom("foo[.bar]")).isEqualTo("foo"); |
||||
} |
||||
|
||||
@Test |
||||
void removeFromWhenHasNoHint() { |
||||
assertThat(FileExtensionHint.removeFrom("foo[bar]")).isEqualTo("foo[bar]"); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,88 @@
@@ -0,0 +1,88 @@
|
||||
/* |
||||
* Copyright 2012-2025 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.boot.context.config; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.boot.env.PropertiesPropertySourceLoader; |
||||
import org.springframework.boot.env.PropertySourceLoader; |
||||
import org.springframework.boot.env.YamlPropertySourceLoader; |
||||
import org.springframework.core.env.PropertySource; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Tests for {@link SystemEnvironmentConfigDataResource}. |
||||
* |
||||
* @author Moritz Halbritter |
||||
*/ |
||||
class SystemEnvironmentConfigDataResourceTests { |
||||
|
||||
private Map<String, String> environment = new HashMap<>(); |
||||
|
||||
private final YamlPropertySourceLoader yamlLoader = new YamlPropertySourceLoader(); |
||||
|
||||
private final PropertiesPropertySourceLoader propertiesLoader = new PropertiesPropertySourceLoader(); |
||||
|
||||
@Test |
||||
void loadLoadsPropertySources() throws IOException { |
||||
this.environment.put("VAR1", "key1=value1"); |
||||
List<PropertySource<?>> loaded = createResource("VAR1").load(); |
||||
assertThat(loaded).hasSize(1); |
||||
assertThat(loaded.get(0).getProperty("key1")).isEqualTo("value1"); |
||||
} |
||||
|
||||
@Test |
||||
void loadWhenNoContentReturnsNull() throws IOException { |
||||
List<PropertySource<?>> loaded = createResource("VAR1").load(); |
||||
assertThat(loaded).isNull(); |
||||
} |
||||
|
||||
@Test |
||||
void equalsAndHashcode() { |
||||
SystemEnvironmentConfigDataResource var1 = createResource("VAR1"); |
||||
SystemEnvironmentConfigDataResource var2 = createResource("VAR2"); |
||||
SystemEnvironmentConfigDataResource var3 = createResource("VAR1", this.yamlLoader); |
||||
SystemEnvironmentConfigDataResource var4 = createResource("VAR1"); |
||||
assertThat(var1).isNotEqualTo(var2); |
||||
assertThat(var1).isNotEqualTo(var3); |
||||
assertThat(var1).isEqualTo(var4); |
||||
assertThat(var1).hasSameHashCodeAs(var4); |
||||
} |
||||
|
||||
@Test |
||||
void toStringReturnsString() { |
||||
SystemEnvironmentConfigDataResource resource = createResource("VAR1"); |
||||
assertThat(resource) |
||||
.hasToString("system envionement variable [VAR1] content loaded using PropertiesPropertySourceLoader"); |
||||
} |
||||
|
||||
private SystemEnvironmentConfigDataResource createResource(String variableName) { |
||||
return createResource(variableName, this.propertiesLoader); |
||||
} |
||||
|
||||
private SystemEnvironmentConfigDataResource createResource(String variableName, |
||||
PropertySourceLoader propertySourceLoader) { |
||||
return new SystemEnvironmentConfigDataResource(variableName, propertySourceLoader, this.environment::get); |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue