diff --git a/spring-boot/src/main/java/org/springframework/boot/env/YamlPropertySourceLoader.java b/spring-boot/src/main/java/org/springframework/boot/env/YamlPropertySourceLoader.java index e12004d4e47..0fdd253ae13 100644 --- a/spring-boot/src/main/java/org/springframework/boot/env/YamlPropertySourceLoader.java +++ b/spring-boot/src/main/java/org/springframework/boot/env/YamlPropertySourceLoader.java @@ -17,11 +17,14 @@ package org.springframework.boot.env; import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; import java.util.Properties; +import org.springframework.beans.factory.config.YamlProcessor; import org.springframework.beans.factory.config.YamlPropertiesFactoryBean; import org.springframework.boot.yaml.SpringProfileDocumentMatcher; -import org.springframework.core.env.PropertiesPropertySource; +import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.PropertySource; import org.springframework.core.io.Resource; import org.springframework.util.ClassUtils; @@ -43,22 +46,44 @@ public class YamlPropertySourceLoader implements PropertySourceLoader { public PropertySource load(String name, Resource resource, String profile) throws IOException { if (ClassUtils.isPresent("org.yaml.snakeyaml.Yaml", null)) { - YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean(); + Processor processor = new Processor(resource, profile); + Map source = processor.process(); + if (!source.isEmpty()) { + return new MapPropertySource(name, source); + } + } + return null; + } + + /** + * {@link YamlProcessor} to create a {@link Map} containing the property values. + * Similar to {@link YamlPropertiesFactoryBean} but retains the order of entries. + */ + private static class Processor extends YamlProcessor { + + public Processor(Resource resource, String profile) { if (profile == null) { - factory.setMatchDefault(true); - factory.setDocumentMatchers(new SpringProfileDocumentMatcher()); + setMatchDefault(true); + setDocumentMatchers(new SpringProfileDocumentMatcher()); } else { - factory.setMatchDefault(false); - factory.setDocumentMatchers(new SpringProfileDocumentMatcher(profile)); - } - factory.setResources(new Resource[] { resource }); - Properties properties = factory.getObject(); - if (!properties.isEmpty()) { - return new PropertiesPropertySource(name, properties); + setMatchDefault(false); + setDocumentMatchers(new SpringProfileDocumentMatcher(profile)); } + setResources(new Resource[] { resource }); } - return null; + + public Map process() { + final Map result = new LinkedHashMap(); + process(new MatchCallback() { + @Override + public void process(Properties properties, Map map) { + result.putAll(map); + } + }); + return getFlattenedMap(result); + } + } } diff --git a/spring-boot/src/test/java/org/springframework/boot/env/YamlPropertySourceLoaderTests.java b/spring-boot/src/test/java/org/springframework/boot/env/YamlPropertySourceLoaderTests.java index a1be14a7570..45e8cfe1689 100644 --- a/spring-boot/src/test/java/org/springframework/boot/env/YamlPropertySourceLoaderTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/env/YamlPropertySourceLoaderTests.java @@ -16,17 +16,24 @@ package org.springframework.boot.env; +import java.util.ArrayList; +import java.util.List; + import org.junit.Test; +import org.springframework.core.env.EnumerablePropertySource; import org.springframework.core.env.PropertySource; import org.springframework.core.io.ByteArrayResource; +import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; /** * Tests for {@link YamlPropertySourceLoader}. * * @author Dave Syer + * @author Phillip Webb */ public class YamlPropertySourceLoaderTests { @@ -40,4 +47,18 @@ public class YamlPropertySourceLoaderTests { assertEquals("spam", source.getProperty("foo.bar")); } + @Test + public void orderedItems() throws Exception { + StringBuilder yaml = new StringBuilder(); + List expected = new ArrayList(); + for (char c = 'a'; c <= 'z'; c++) { + yaml.append(c + ": value" + c + "\n"); + expected.add(String.valueOf(c)); + } + ByteArrayResource resource = new ByteArrayResource(yaml.toString().getBytes()); + EnumerablePropertySource source = (EnumerablePropertySource) this.loader + .load("resource", resource, null); + assertNotNull(source); + assertThat(source.getPropertyNames(), equalTo(expected.toArray(new String[] {}))); + } }