Commit 8ec3ca74 authored by Madhura Bhave's avatar Madhura Bhave

Fix loading of devtools yaml files

Fixes gh-19081
parent 9c413689
...@@ -206,6 +206,11 @@ ...@@ -206,6 +206,11 @@
<artifactId>thymeleaf-spring5</artifactId> <artifactId>thymeleaf-spring5</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>nz.net.ultraq.thymeleaf</groupId> <groupId>nz.net.ultraq.thymeleaf</groupId>
<artifactId>thymeleaf-layout-dialect</artifactId> <artifactId>thymeleaf-layout-dialect</artifactId>
......
...@@ -19,18 +19,23 @@ package org.springframework.boot.devtools.env; ...@@ -19,18 +19,23 @@ package org.springframework.boot.devtools.env;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Properties; import java.util.Set;
import java.util.function.Function; import java.util.function.Function;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.devtools.system.DevToolsEnablementDeducer; import org.springframework.boot.devtools.system.DevToolsEnablementDeducer;
import org.springframework.boot.env.EnvironmentPostProcessor; import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.boot.env.PropertiesPropertySourceLoader;
import org.springframework.boot.env.PropertySourceLoader;
import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource; import org.springframework.core.env.PropertySource;
import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.support.PropertiesLoaderUtils; import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
...@@ -52,6 +57,17 @@ public class DevToolsHomePropertiesPostProcessor implements EnvironmentPostProce ...@@ -52,6 +57,17 @@ public class DevToolsHomePropertiesPostProcessor implements EnvironmentPostProce
private static final String CONFIG_PATH = "/.config/spring-boot/"; private static final String CONFIG_PATH = "/.config/spring-boot/";
private static final Set<PropertySourceLoader> PROPERTY_SOURCE_LOADERS;
static {
Set<PropertySourceLoader> propertySourceLoaders = new HashSet<>();
propertySourceLoaders.add(new PropertiesPropertySourceLoader());
if (ClassUtils.isPresent("org.yaml.snakeyaml.Yaml", null)) {
propertySourceLoaders.add(new YamlPropertySourceLoader());
}
PROPERTY_SOURCE_LOADERS = Collections.unmodifiableSet(propertySourceLoaders);
}
@Override @Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
if (DevToolsEnablementDeducer.shouldEnable(Thread.currentThread())) { if (DevToolsEnablementDeducer.shouldEnable(Thread.currentThread())) {
...@@ -88,15 +104,23 @@ public class DevToolsHomePropertiesPostProcessor implements EnvironmentPostProce ...@@ -88,15 +104,23 @@ public class DevToolsHomePropertiesPostProcessor implements EnvironmentPostProce
private void addPropertySource(List<PropertySource<?>> propertySources, FileSystemResource resource, private void addPropertySource(List<PropertySource<?>> propertySources, FileSystemResource resource,
Function<File, String> propertySourceNamer) { Function<File, String> propertySourceNamer) {
try { try {
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
String name = propertySourceNamer.apply(resource.getFile()); String name = propertySourceNamer.apply(resource.getFile());
propertySources.add(new PropertiesPropertySource(name, properties)); for (PropertySourceLoader loader : PROPERTY_SOURCE_LOADERS) {
if (canLoadFileExtension(loader, resource.getFilename())) {
propertySources.addAll(loader.load(name, resource));
}
}
} }
catch (IOException ex) { catch (IOException ex) {
throw new IllegalStateException("Unable to load " + resource.getFilename(), ex); throw new IllegalStateException("Unable to load " + resource.getFilename(), ex);
} }
} }
private boolean canLoadFileExtension(PropertySourceLoader loader, String name) {
return Arrays.stream(loader.getFileExtensions())
.anyMatch((fileExtension) -> StringUtils.endsWithIgnoreCase(name, fileExtension));
}
protected File getHomeFolder() { protected File getHomeFolder() {
String home = System.getProperty("user.home"); String home = System.getProperty("user.home");
if (StringUtils.hasLength(home)) { if (StringUtils.hasLength(home)) {
......
...@@ -20,6 +20,7 @@ import java.io.File; ...@@ -20,6 +20,7 @@ import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.file.Files;
import java.util.Properties; import java.util.Properties;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
...@@ -27,6 +28,7 @@ import org.junit.jupiter.api.Test; ...@@ -27,6 +28,7 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.io.TempDir;
import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.mock.env.MockEnvironment; import org.springframework.mock.env.MockEnvironment;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
...@@ -74,42 +76,41 @@ class DevToolsHomePropertiesPostProcessorTests { ...@@ -74,42 +76,41 @@ class DevToolsHomePropertiesPostProcessorTests {
@Test @Test
void loadsPropertiesFromConfigFolderUsingYml() throws Exception { void loadsPropertiesFromConfigFolderUsingYml() throws Exception {
Properties properties = new Properties();
properties.put("abc", "def");
OutputStream out = new FileOutputStream(new File(this.configDir, "spring-boot-devtools.yml")); OutputStream out = new FileOutputStream(new File(this.configDir, "spring-boot-devtools.yml"));
properties.store(out, null); File file = new ClassPathResource("spring-devtools.yaml", getClass()).getFile();
byte[] content = Files.readAllBytes(file.toPath());
out.write(content);
out.close(); out.close();
ConfigurableEnvironment environment = getPostProcessedEnvironment(); ConfigurableEnvironment environment = getPostProcessedEnvironment();
assertThat(environment.getProperty("abc")).isEqualTo("def"); assertThat(environment.getProperty("abc.xyz")).isEqualTo("def");
} }
@Test @Test
void loadsPropertiesFromConfigFolderUsingYaml() throws Exception { void loadsPropertiesFromConfigFolderUsingYaml() throws Exception {
Properties properties = new Properties();
properties.put("abc", "def");
OutputStream out = new FileOutputStream(new File(this.configDir, "spring-boot-devtools.yaml")); OutputStream out = new FileOutputStream(new File(this.configDir, "spring-boot-devtools.yaml"));
properties.store(out, null); File file = new ClassPathResource("spring-devtools.yaml", getClass()).getFile();
byte[] content = Files.readAllBytes(file.toPath());
out.write(content);
out.close(); out.close();
ConfigurableEnvironment environment = getPostProcessedEnvironment(); ConfigurableEnvironment environment = getPostProcessedEnvironment();
assertThat(environment.getProperty("abc")).isEqualTo("def"); assertThat(environment.getProperty("abc.xyz")).isEqualTo("def");
} }
@Test @Test
void loadFromConfigFolderWithPropertiesTakingPrecedence() throws Exception { void loadFromConfigFolderWithPropertiesTakingPrecedence() throws Exception {
Properties properties = new Properties();
properties.put("abc", "def");
properties.put("bar", "baz");
OutputStream out = new FileOutputStream(new File(this.configDir, "spring-boot-devtools.yaml")); OutputStream out = new FileOutputStream(new File(this.configDir, "spring-boot-devtools.yaml"));
properties.store(out, null); File file = new ClassPathResource("spring-devtools.yaml", getClass()).getFile();
byte[] content = Files.readAllBytes(file.toPath());
out.write(content);
out.close(); out.close();
Properties properties2 = new Properties(); Properties properties2 = new Properties();
properties2.put("abc", "jkl"); properties2.put("abc.xyz", "jkl");
OutputStream out2 = new FileOutputStream(new File(this.configDir, "spring-boot-devtools.properties")); OutputStream out2 = new FileOutputStream(new File(this.configDir, "spring-boot-devtools.properties"));
properties2.store(out2, null); properties2.store(out2, null);
out2.close(); out2.close();
ConfigurableEnvironment environment = getPostProcessedEnvironment(); ConfigurableEnvironment environment = getPostProcessedEnvironment();
assertThat(environment.getProperty("abc")).isEqualTo("jkl"); assertThat(environment.getProperty("abc.xyz")).isEqualTo("jkl");
assertThat(environment.getProperty("bar")).isEqualTo("baz"); assertThat(environment.getProperty("bing")).isEqualTo("blip");
} }
@Test @Test
...@@ -131,16 +132,16 @@ class DevToolsHomePropertiesPostProcessorTests { ...@@ -131,16 +132,16 @@ class DevToolsHomePropertiesPostProcessorTests {
@Test @Test
void loadFromConfigFolderWithYamlTakesPrecedenceOverHomeFolder() throws Exception { void loadFromConfigFolderWithYamlTakesPrecedenceOverHomeFolder() throws Exception {
Properties properties = new Properties(); Properties properties = new Properties();
properties.put("abc", "def"); properties.put("abc.xyz", "jkl");
properties.put("bar", "baz"); properties.put("bar", "baz");
writeFile(properties, ".spring-boot-devtools.properties"); writeFile(properties, ".spring-boot-devtools.properties");
Properties properties2 = new Properties();
properties2.put("abc", "jkl");
OutputStream out2 = new FileOutputStream(new File(this.configDir, "spring-boot-devtools.yml")); OutputStream out2 = new FileOutputStream(new File(this.configDir, "spring-boot-devtools.yml"));
properties2.store(out2, null); File file = new ClassPathResource("spring-devtools.yaml", getClass()).getFile();
byte[] content = Files.readAllBytes(file.toPath());
out2.write(content);
out2.close(); out2.close();
ConfigurableEnvironment environment = getPostProcessedEnvironment(); ConfigurableEnvironment environment = getPostProcessedEnvironment();
assertThat(environment.getProperty("abc")).isEqualTo("jkl"); assertThat(environment.getProperty("abc.xyz")).isEqualTo("def");
assertThat(environment.getProperty("bar")).isEqualTo(null); assertThat(environment.getProperty("bar")).isEqualTo(null);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment