Skip to content

Commit b43972b

Browse files
committed
Preserve property ordering for text blocks in @TestPropertySource
See gh-31053
1 parent 17109b2 commit b43972b

File tree

2 files changed

+33
-23
lines changed

2 files changed

+33
-23
lines changed

spring-test/src/main/java/org/springframework/test/context/support/TestPropertySourceUtils.java

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -373,12 +373,11 @@ public static void addInlinedPropertiesToEnvironment(ConfigurableEnvironment env
373373
* <p>Parsing of the key-value pairs is achieved by converting all supplied
374374
* strings into <em>virtual</em> properties files in memory and delegating to
375375
* {@link Properties#load(java.io.Reader)} to parse each virtual file.
376-
* <p>Generally speaking, the ordering of property names will be preserved in
377-
* the returned map, analogous to the order in which the key-value pairs are
378-
* supplied to this method. However, if a single string contains multiple
379-
* key-value pairs separated by newlines &mdash; for example, when supplied by
380-
* a user via a <em>text block</em> &mdash; the ordering of property names for
381-
* those particular key-value pairs cannot be guaranteed in the returned map.
376+
* <p>The ordering of property names will be preserved in the returned map,
377+
* analogous to the order in which the key-value pairs are supplied to this
378+
* method. This also applies if a single string contains multiple key-value
379+
* pairs separated by newlines &mdash; for example, when supplied by a user
380+
* via a <em>text block</em>.
382381
* <p>For a full discussion of <em>inlined properties</em>, consult the Javadoc
383382
* for {@link TestPropertySource#properties}.
384383
* @param inlinedProperties the inlined properties to convert; potentially empty
@@ -390,26 +389,21 @@ public static void addInlinedPropertiesToEnvironment(ConfigurableEnvironment env
390389
*/
391390
public static Map<String, Object> convertInlinedPropertiesToMap(String... inlinedProperties) {
392391
Assert.notNull(inlinedProperties, "'inlinedProperties' must not be null");
393-
Map<String, Object> map = new LinkedHashMap<>();
394-
Properties props = new Properties();
392+
SequencedProperties sequencedProperties = new SequencedProperties();
395393

396-
for (String pair : inlinedProperties) {
397-
if (!StringUtils.hasText(pair)) {
394+
for (String input : inlinedProperties) {
395+
if (!StringUtils.hasText(input)) {
398396
continue;
399397
}
400398
try {
401-
props.load(new StringReader(pair));
399+
sequencedProperties.load(new StringReader(input));
402400
}
403401
catch (Exception ex) {
404-
throw new IllegalStateException("Failed to load test environment properties from [" + pair + "]", ex);
402+
throw new IllegalStateException("Failed to load test environment properties from [" + input + "]", ex);
405403
}
406-
for (String name : props.stringPropertyNames()) {
407-
map.put(name, props.getProperty(name));
408-
}
409-
props.clear();
410404
}
411405

412-
return map;
406+
return sequencedProperties.map;
413407
}
414408

415409
private static <T extends Annotation> List<List<MergedAnnotation<T>>> findRepeatableAnnotations(
@@ -456,4 +450,24 @@ private static <A extends Annotation> Comparator<MergedAnnotation<A>> highMetaDi
456450
return Comparator.<MergedAnnotation<A>> comparingInt(MergedAnnotation::getDistance).reversed();
457451
}
458452

453+
/**
454+
* Extension of {@link Properties} that mimics a {@code SequencedMap} by
455+
* tracking all added properties in a {@link LinkedHashMap} that can be
456+
* accessed directly via the {@code map} field.
457+
* @since 6.1
458+
*/
459+
@SuppressWarnings("serial")
460+
private static class SequencedProperties extends Properties {
461+
462+
final Map<String, Object> map = new LinkedHashMap<>();
463+
464+
@Override
465+
public synchronized Object put(Object key, Object value) {
466+
if (key instanceof String str) {
467+
this.map.put(str, value);
468+
}
469+
return super.put(key, value);
470+
}
471+
}
472+
459473
}

spring-test/src/test/java/org/springframework/test/context/env/InlinedPropertiesWithTextBlockTestPropertySourceTests.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,16 +78,12 @@ void propertiesAreAvailableInEnvironment() {
7878
assertEnvironmentProperty(this.env, "key.value.3", "key:value");
7979
}
8080

81-
/**
82-
* Not necessarily preserved because the properties are all added at the
83-
* same time.
84-
*/
8581
@Test
8682
@SuppressWarnings("rawtypes")
87-
void propertyNameOrderingIsNotNecessarilyPreservedInEnvironment() {
83+
void propertyNameOrderingIsPreservedInEnvironment() {
8884
EnumerablePropertySource eps = (EnumerablePropertySource) env.getPropertySources().get(
8985
INLINED_PROPERTIES_PROPERTY_SOURCE_NAME);
90-
assertThat(eps.getPropertyNames()).containsExactlyInAnyOrder("foo", "baz", "enigma", "x.y.z",
86+
assertThat(eps.getPropertyNames()).containsExactly("foo", "baz", "enigma", "x.y.z",
9187
"server.url", "key.value.1", "key.value.2", "key.value.3");
9288
}
9389

0 commit comments

Comments
 (0)