jamesfredley commented on code in PR #16772:
URL: https://github.com/apache/grails-core/pull/16772#discussion_r4396159240
##########
grails-bootstrap/src/main/groovy/org/grails/config/NavigableMap.groovy:
##########
@@ -374,15 +375,103 @@ class NavigableMap implements Map<String, Object>,
Cloneable {
Map<String, Object> toFlatConfig() {
Map<String, Object> flatConfig = [:]
flattenKeys(flatConfig, this, [], false)
+ removeDottedDuplicates(flatConfig)
flatConfig
}
Properties toProperties() {
Properties properties = new Properties()
flattenKeys((Map<Object, Object>) properties, this, [], true)
+ removeDottedDuplicates((Map<Object, Object>) properties)
properties
}
+ /**
+ * Removes each name that only writes a bracketed name with dots, such as
{@code app.routes./api/**} beside
+ * {@code app.routes[/api/**]}, which Spring Boot would bind as the key
{@code api}. A map written by map subscripts
+ * holds its entries under their bracketed names and is walked under their
dotted ones too, so each entry is
+ * flattened under both. A dotted name is removed only when every
bracketed name that it writes with dots holds the
+ * same value; where they differ, as when a later write changed one of
them, every name stays, as it was before. A
+ * bracketed key with a dot in it, {@code a[b.c]}, names a key of {@code
a}, so the dotted name {@code a.b.c} is
+ * a property of its own, and it stays when the nested maps hold a value
under that path.
+ */
+ private void removeDottedDuplicates(Map<? extends Object, Object>
flatConfig) {
+ Map<String, List<Object>> bracketedValues = [:]
+ Set<String> pathsToCheck = [] as Set<String>
+ for (Map.Entry<? extends Object, Object> entry in
flatConfig.entrySet()) {
+ String name = String.valueOf(entry.key)
+ if (name.indexOf('[') > -1) {
+ for (Map.Entry<String, Boolean> dottedName in
dottedNamesOf(name).entrySet()) {
+ List<Object> values = bracketedValues.get(dottedName.key)
+ if (values == null) {
+ values = []
+ bracketedValues.put(dottedName.key, values)
+ }
+ values.add(entry.value)
+ if (dottedName.value) {
+ pathsToCheck.add(dottedName.key)
+ }
+ }
+ }
+ }
+ for (Map.Entry<String, List<Object>> candidate in
bracketedValues.entrySet()) {
+ if (!flatConfig.containsKey(candidate.key)) {
+ continue
+ }
+ Object value = flatConfig.get(candidate.key)
+ if (!candidate.value.every { Object bracketedValue ->
bracketedValue == value }) {
+ continue
+ }
+ if (candidate.key in pathsToCheck &&
navigate(candidate.key.tokenize('.') as String[]) != null) {
Review Comment:
put('a.b.c', 'x') then merge(['a[b.c]': 'x']) removes a.b.c from
toProperties(). Those names are not the same path: a[b.c] is the key b.c, and
a.b.c is the nested property. navigate does not see the flat put, so this check
treats it as a duplicate.
Keep a flat key that was stored on its own. Please assert both names stay.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]