Skip to content

Commit 87f1512

Browse files
committed
Add protected YamlProcessor.getFlattenedMap method
Add a protected getFlattenedMap method to the YamlProcessor that subclasses can use to flatten a source Map so that it has the same entries as the Properties, but retains order. Issue: SPR-12499
1 parent 83ecf5c commit 87f1512

File tree

2 files changed

+43
-8
lines changed

2 files changed

+43
-8
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/config/YamlProcessor.java

+22-7
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ private Map<String, Object> asMap(Object object) {
212212

213213
private boolean process(Map<String, Object> map, MatchCallback callback) {
214214
Properties properties = new Properties();
215-
assignProperties(properties, map, null);
215+
properties.putAll(getFlattenedMap(map));
216216

217217
if (this.documentMatchers.isEmpty()) {
218218
if (this.logger.isDebugEnabled()) {
@@ -247,8 +247,23 @@ private boolean process(Map<String, Object> map, MatchCallback callback) {
247247
return false;
248248
}
249249

250-
private void assignProperties(Properties properties, Map<String, Object> input, String path) {
251-
for (Entry<String, Object> entry : input.entrySet()) {
250+
/**
251+
* Return a flattened version of the given map, recursively following any nested Map
252+
* or Collection values. Entries from the resulting map retain the same order as the
253+
* source. When called with the Map from a {@link MatchCallback} the result will
254+
* contain the same values as the {@link MatchCallback} Properties.
255+
* @param source the source map
256+
* @return a flattened map
257+
* @since 4.2.3
258+
*/
259+
protected final Map<String, Object> getFlattenedMap(Map<String, Object> source) {
260+
Map<String, Object> result = new LinkedHashMap<String, Object>();
261+
buildFlattenedMap(result, source, null);
262+
return result;
263+
}
264+
265+
private void buildFlattenedMap(Map<String, Object> result, Map<String, Object> source, String path) {
266+
for (Entry<String, Object> entry : source.entrySet()) {
252267
String key = entry.getKey();
253268
if (StringUtils.hasText(path)) {
254269
if (key.startsWith("[")) {
@@ -260,26 +275,26 @@ private void assignProperties(Properties properties, Map<String, Object> input,
260275
}
261276
Object value = entry.getValue();
262277
if (value instanceof String) {
263-
properties.put(key, value);
278+
result.put(key, value);
264279
}
265280
else if (value instanceof Map) {
266281
// Need a compound key
267282
@SuppressWarnings("unchecked")
268283
Map<String, Object> map = (Map<String, Object>) value;
269-
assignProperties(properties, map, key);
284+
buildFlattenedMap(result, map, key);
270285
}
271286
else if (value instanceof Collection) {
272287
// Need a compound key
273288
@SuppressWarnings("unchecked")
274289
Collection<Object> collection = (Collection<Object>) value;
275290
int count = 0;
276291
for (Object object : collection) {
277-
assignProperties(properties,
292+
buildFlattenedMap(result,
278293
Collections.singletonMap("[" + (count++) + "]", object), key);
279294
}
280295
}
281296
else {
282-
properties.put(key, value == null ? "" : value);
297+
result.put(key, value == null ? "" : value);
283298
}
284299
}
285300
}

spring-beans/src/test/java/org/springframework/beans/factory/config/YamlProcessorTests.java

+21-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package org.springframework.beans.factory.config;
1717

18+
import java.util.LinkedHashMap;
1819
import java.util.Map;
1920
import java.util.Properties;
2021

@@ -23,7 +24,6 @@
2324
import org.junit.rules.ExpectedException;
2425
import org.yaml.snakeyaml.parser.ParserException;
2526
import org.yaml.snakeyaml.scanner.ScannerException;
26-
2727
import org.springframework.core.io.ByteArrayResource;
2828

2929
import static org.junit.Assert.*;
@@ -135,4 +135,24 @@ public void process(Properties properties, Map<String, Object> map) {
135135
}
136136
});
137137
}
138+
139+
@Test
140+
@SuppressWarnings("unchecked")
141+
public void flattenedMapIsSameAsPropertiesButOrdered() {
142+
this.processor.setResources(new ByteArrayResource(
143+
"foo: bar\nbar:\n spam: bucket".getBytes()));
144+
this.processor.process(new MatchCallback() {
145+
@Override
146+
public void process(Properties properties, Map<String, Object> map) {
147+
assertEquals("bucket", properties.get("bar.spam"));
148+
assertEquals(2, properties.size());
149+
Map<String, Object> flattenedMap = processor.getFlattenedMap(map);
150+
assertEquals("bucket", flattenedMap.get("bar.spam"));
151+
assertEquals(2, flattenedMap.size());
152+
assertTrue(flattenedMap instanceof LinkedHashMap);
153+
Map<String, Object> bar = (Map<String, Object>) map.get("bar");
154+
assertEquals("bucket", bar.get("spam"));
155+
}
156+
});
157+
}
138158
}

0 commit comments

Comments
 (0)