diff --git a/spring-boot-project/spring-boot-devtools/pom.xml b/spring-boot-project/spring-boot-devtools/pom.xml index ec2c76f602cc..9af7e352ad79 100644 --- a/spring-boot-project/spring-boot-devtools/pom.xml +++ b/spring-boot-project/spring-boot-devtools/pom.xml @@ -206,6 +206,11 @@ thymeleaf-spring5 test + + org.yaml + snakeyaml + test + nz.net.ultraq.thymeleaf thymeleaf-layout-dialect diff --git a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/env/DevToolsHomePropertiesPostProcessor.java b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/env/DevToolsHomePropertiesPostProcessor.java index 8c1a4e5069cc..4305ef20d441 100644 --- a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/env/DevToolsHomePropertiesPostProcessor.java +++ b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/env/DevToolsHomePropertiesPostProcessor.java @@ -19,18 +19,23 @@ import java.io.File; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; import java.util.List; -import java.util.Properties; +import java.util.Set; import java.util.function.Function; import org.springframework.boot.SpringApplication; import org.springframework.boot.devtools.system.DevToolsEnablementDeducer; 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.PropertiesPropertySource; import org.springframework.core.env.PropertySource; import org.springframework.core.io.FileSystemResource; -import org.springframework.core.io.support.PropertiesLoaderUtils; +import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; /** @@ -52,6 +57,17 @@ public class DevToolsHomePropertiesPostProcessor implements EnvironmentPostProce private static final String CONFIG_PATH = "/.config/spring-boot/"; + private static final Set PROPERTY_SOURCE_LOADERS; + + static { + Set 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 public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { if (DevToolsEnablementDeducer.shouldEnable(Thread.currentThread())) { @@ -88,15 +104,23 @@ private void addPropertySource(List> propertySources, String f private void addPropertySource(List> propertySources, FileSystemResource resource, Function propertySourceNamer) { try { - Properties properties = PropertiesLoaderUtils.loadProperties(resource); 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) { 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() { String home = System.getProperty("user.home"); if (StringUtils.hasLength(home)) { diff --git a/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/env/DevToolsHomePropertiesPostProcessorTests.java b/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/env/DevToolsHomePropertiesPostProcessorTests.java index 65e7eb29da04..daa7796bdc35 100644 --- a/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/env/DevToolsHomePropertiesPostProcessorTests.java +++ b/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/env/DevToolsHomePropertiesPostProcessorTests.java @@ -20,6 +20,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; +import java.nio.file.Files; import java.util.Properties; import org.junit.jupiter.api.BeforeEach; @@ -27,6 +28,7 @@ import org.junit.jupiter.api.io.TempDir; import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.io.ClassPathResource; import org.springframework.mock.env.MockEnvironment; import static org.assertj.core.api.Assertions.assertThat; @@ -74,42 +76,41 @@ void loadsPropertiesFromConfigFolderUsingProperties() throws Exception { @Test void loadsPropertiesFromConfigFolderUsingYml() throws Exception { - Properties properties = new Properties(); - properties.put("abc", "def"); 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(); ConfigurableEnvironment environment = getPostProcessedEnvironment(); - assertThat(environment.getProperty("abc")).isEqualTo("def"); + assertThat(environment.getProperty("abc.xyz")).isEqualTo("def"); } @Test void loadsPropertiesFromConfigFolderUsingYaml() throws Exception { - Properties properties = new Properties(); - properties.put("abc", "def"); 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(); ConfigurableEnvironment environment = getPostProcessedEnvironment(); - assertThat(environment.getProperty("abc")).isEqualTo("def"); + assertThat(environment.getProperty("abc.xyz")).isEqualTo("def"); } @Test 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")); - properties.store(out, null); + File file = new ClassPathResource("spring-devtools.yaml", getClass()).getFile(); + byte[] content = Files.readAllBytes(file.toPath()); + out.write(content); out.close(); 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")); properties2.store(out2, null); out2.close(); ConfigurableEnvironment environment = getPostProcessedEnvironment(); - assertThat(environment.getProperty("abc")).isEqualTo("jkl"); - assertThat(environment.getProperty("bar")).isEqualTo("baz"); + assertThat(environment.getProperty("abc.xyz")).isEqualTo("jkl"); + assertThat(environment.getProperty("bing")).isEqualTo("blip"); } @Test @@ -131,16 +132,16 @@ void loadFromConfigFolderTakesPrecedenceOverHomeFolder() throws Exception { @Test void loadFromConfigFolderWithYamlTakesPrecedenceOverHomeFolder() throws Exception { Properties properties = new Properties(); - properties.put("abc", "def"); + properties.put("abc.xyz", "jkl"); properties.put("bar", "baz"); 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")); - properties2.store(out2, null); + File file = new ClassPathResource("spring-devtools.yaml", getClass()).getFile(); + byte[] content = Files.readAllBytes(file.toPath()); + out2.write(content); out2.close(); ConfigurableEnvironment environment = getPostProcessedEnvironment(); - assertThat(environment.getProperty("abc")).isEqualTo("jkl"); + assertThat(environment.getProperty("abc.xyz")).isEqualTo("def"); assertThat(environment.getProperty("bar")).isEqualTo(null); } diff --git a/spring-boot-project/spring-boot-devtools/src/test/resources/org/springframework/boot/devtools/env/spring-devtools.yaml b/spring-boot-project/spring-boot-devtools/src/test/resources/org/springframework/boot/devtools/env/spring-devtools.yaml new file mode 100644 index 000000000000..80d448fbfef9 --- /dev/null +++ b/spring-boot-project/spring-boot-devtools/src/test/resources/org/springframework/boot/devtools/env/spring-devtools.yaml @@ -0,0 +1,3 @@ +abc: + xyz: def +bing: blip \ No newline at end of file