Commit 39ee5839 authored by Phillip Webb's avatar Phillip Webb

Retain YAML property ordering

Update YamlPropertySourceLoader to use a MapPropertySource rather than
a PropertiesPropertySource to ensure that the underlying order is
retained.

Fixes gh-2022
parent 6c96608b
......@@ -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<String, Object> 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<String, Object> process() {
final Map<String, Object> result = new LinkedHashMap<String, Object>();
process(new MatchCallback() {
@Override
public void process(Properties properties, Map<String, Object> map) {
result.putAll(map);
}
});
return getFlattenedMap(result);
}
}
}
......@@ -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<String> expected = new ArrayList<String>();
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[] {})));
}
}
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