diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/config/YamlProcessorTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/config/YamlProcessorTests.java index a16c1a719a..175f9ca17f 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/config/YamlProcessorTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/config/YamlProcessorTests.java @@ -17,6 +17,7 @@ package org.springframework.beans.factory.config; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import org.junit.Test; @@ -25,6 +26,7 @@ import org.yaml.snakeyaml.scanner.ScannerException; import org.springframework.core.io.ByteArrayResource; +import static java.util.stream.Collectors.toList; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -33,6 +35,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; * * @author Dave Syer * @author Juergen Hoeller + * @author Sam Brannen */ public class YamlProcessorTests { @@ -107,17 +110,27 @@ public class YamlProcessorTests { @Test @SuppressWarnings("unchecked") public void flattenedMapIsSameAsPropertiesButOrdered() { - this.processor.setResources(new ByteArrayResource("foo: bar\nbar:\n spam: bucket".getBytes())); + this.processor.setResources(new ByteArrayResource("cat: dog\nfoo: bar\nbar:\n spam: bucket".getBytes())); this.processor.process((properties, map) -> { - assertThat(properties.get("bar.spam")).isEqualTo("bucket"); - assertThat(properties).hasSize(2); Map flattenedMap = processor.getFlattenedMap(map); + assertThat(flattenedMap).isInstanceOf(LinkedHashMap.class); + + assertThat(properties).hasSize(3); + assertThat(flattenedMap).hasSize(3); + + assertThat(properties.get("bar.spam")).isEqualTo("bucket"); assertThat(flattenedMap.get("bar.spam")).isEqualTo("bucket"); - assertThat(flattenedMap.size()).isEqualTo(2); - boolean condition = flattenedMap instanceof LinkedHashMap; - assertThat(condition).isTrue(); + Map bar = (Map) map.get("bar"); assertThat(bar.get("spam")).isEqualTo("bucket"); + + List keysFromProperties = properties.keySet().stream().collect(toList()); + List keysFromFlattenedMap = flattenedMap.keySet().stream().collect(toList()); + assertThat(keysFromProperties).containsExactlyInAnyOrderElementsOf(keysFromFlattenedMap); + // Keys in the Properties object are sorted. + assertThat(keysFromProperties).containsExactly("bar.spam", "cat", "foo"); + // But the flattened map retains the order from the input. + assertThat(keysFromFlattenedMap).containsExactly("cat", "foo", "bar.spam"); }); } diff --git a/spring-core/src/main/java/org/springframework/core/CollectionFactory.java b/spring-core/src/main/java/org/springframework/core/CollectionFactory.java index 6df7b4daac..d131fd2727 100644 --- a/spring-core/src/main/java/org/springframework/core/CollectionFactory.java +++ b/spring-core/src/main/java/org/springframework/core/CollectionFactory.java @@ -329,14 +329,18 @@ public final class CollectionFactory { } /** - * Create a variant of {@code java.util.Properties} that automatically adapts - * non-String values to String representations on {@link Properties#getProperty}. + * Create a variant of {@link java.util.Properties} that automatically adapts + * non-String values to String representations in {@link Properties#getProperty}. + *

In addition, the returned {@code Properties} instance sorts properties + * alphanumerically based on their keys. * @return a new {@code Properties} instance * @since 4.3.4 + * @see #createSortedProperties(boolean) + * @see #createSortedProperties(Properties, boolean) */ @SuppressWarnings("serial") public static Properties createStringAdaptingProperties() { - return new Properties() { + return new SortedProperties(false) { @Override @Nullable public String getProperty(String key) { @@ -359,6 +363,7 @@ public final class CollectionFactory { * storing properties in a file * @return a new {@code Properties} instance * @since 5.2 + * @see #createStringAdaptingProperties() * @see #createSortedProperties(Properties, boolean) */ public static Properties createSortedProperties(boolean omitComments) { @@ -384,6 +389,7 @@ public final class CollectionFactory { * storing properties in a file * @return a new {@code Properties} instance * @since 5.2 + * @see #createStringAdaptingProperties() * @see #createSortedProperties(boolean) */ public static Properties createSortedProperties(Properties properties, boolean omitComments) {