mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Allow YAML processors to create a flattened map with nulls included
Add an additional `getFlattenedMap` method to `YamlProcessor` to allow
the resulting flattened map to include nulls.
This update will allow processor subclasses to tell the difference
between YAML that is defined with an empty object vs missing the key
entirely:
e.g.:
application:
name: test
optional: {}
vs
application:
name: test
optional: {}
Closes gh-36197
Signed-off-by: Phillip Webb <phil.webb@broadcom.com>
This commit is contained in:
committed by
Juergen Hoeller
parent
5b4eda3d20
commit
0c9f40b171
+23
-4
@@ -304,13 +304,32 @@ public abstract class YamlProcessor {
|
||||
* @since 4.1.3
|
||||
*/
|
||||
protected final Map<String, Object> getFlattenedMap(Map<String, Object> source) {
|
||||
return getFlattenedMap(source, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a flattened version of the given map, recursively following any nested Map
|
||||
* or Collection values. Entries from the resulting map retain the same order as the
|
||||
* source. When called with the Map from a {@link MatchCallback} the result will
|
||||
* contain the same values as the {@link MatchCallback} Properties.
|
||||
* @param source the source map
|
||||
* @param includeNulls if {@code null} entries can be included in the result
|
||||
* @return a flattened map
|
||||
* @since 7.0.4
|
||||
*/
|
||||
protected final Map<String, Object> getFlattenedMap(Map<String, Object> source, boolean includeNulls) {
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
buildFlattenedMap(result, source, null);
|
||||
buildFlattenedMap(result, source, null, includeNulls);
|
||||
return result;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
private void buildFlattenedMap(Map<String, Object> result, Map<String, Object> source, @Nullable String path) {
|
||||
private void buildFlattenedMap(Map<String, Object> result, Map<String, Object> source, @Nullable String path,
|
||||
boolean includeNulls) {
|
||||
if (includeNulls && source.isEmpty()) {
|
||||
result.put(path, null);
|
||||
return;
|
||||
}
|
||||
source.forEach((key, value) -> {
|
||||
if (StringUtils.hasText(path)) {
|
||||
if (key.startsWith("[")) {
|
||||
@@ -325,7 +344,7 @@ public abstract class YamlProcessor {
|
||||
}
|
||||
else if (value instanceof Map map) {
|
||||
// Need a compound key
|
||||
buildFlattenedMap(result, map, key);
|
||||
buildFlattenedMap(result, map, key, includeNulls);
|
||||
}
|
||||
else if (value instanceof Collection collection) {
|
||||
// Need a compound key
|
||||
@@ -336,7 +355,7 @@ public abstract class YamlProcessor {
|
||||
int count = 0;
|
||||
for (Object object : collection) {
|
||||
buildFlattenedMap(result, Collections.singletonMap(
|
||||
"[" + (count++) + "]", object), key);
|
||||
"[" + (count++) + "]", object), key, includeNulls);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+26
-2
@@ -44,8 +44,7 @@ import static org.assertj.core.api.InstanceOfAssertFactories.set;
|
||||
*/
|
||||
class YamlProcessorTests {
|
||||
|
||||
private final YamlProcessor processor = new YamlProcessor() {
|
||||
};
|
||||
private final TestYamlProcessor processor = new TestYamlProcessor();
|
||||
|
||||
|
||||
@Test
|
||||
@@ -182,8 +181,33 @@ class YamlProcessorTests {
|
||||
.withMessageContaining("Global tag is not allowed: tag:yaml.org,2002:java.net.URL");
|
||||
}
|
||||
|
||||
@Test
|
||||
void processAndFlattenWithoutIncludedNulls() {
|
||||
setYaml("foo: bar\nbar:\n spam: {}");
|
||||
Map<String, Object> flattened = this.processor.processAndFlatten(false);
|
||||
assertThat(flattened).containsEntry("foo", "bar").doesNotContainKey("bar.spam").hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void processAndFlattenWithIncludedNulls() {
|
||||
setYaml("foo: bar\nbar:\n spam: {}");
|
||||
Map<String, Object> flattened = this.processor.processAndFlatten(true);
|
||||
assertThat(flattened).containsEntry("foo", "bar").containsEntry("bar.spam", null).hasSize(2);
|
||||
}
|
||||
|
||||
private void setYaml(String yaml) {
|
||||
this.processor.setResources(new ByteArrayResource(yaml.getBytes()));
|
||||
}
|
||||
|
||||
private static class TestYamlProcessor extends YamlProcessor {
|
||||
|
||||
Map<String, Object> processAndFlatten(boolean includeNulls) {
|
||||
Map<String, Object> flattened = new LinkedHashMap<>();
|
||||
process((properties, map) -> flattened.putAll(getFlattenedMap(map, includeNulls)));
|
||||
return flattened;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user