codeconsole commented on code in PR #16732:
URL: https://github.com/apache/grails-core/pull/16732#discussion_r4368880392


##########
grails-bootstrap/src/main/groovy/org/grails/config/NavigableMap.groovy:
##########
@@ -199,30 +246,160 @@ class NavigableMap implements Map<String, Object>, 
Cloneable {
                 mergeMaps(rootMap, newPath , subMap, (Map) sourceValue, 
parseFlatKeys)
                 newValue = subMap
             } else {
-                newValue = sourceValue
+                newValue = mergedValue(sourceValue)
             }
             if (isNestedSet && newValue == null) {
-                if (path) {
-
-                    def subMap = rootMap.get(path)
-                    if (subMap instanceof Map) {
-                        subMap.remove(sourceKey)
-                    }
-                    def keysToRemove = rootMap.keySet().findAll() { String key 
->
-                        key.startsWith("${path}.")
-                    }
-                    for (key in keysToRemove) {
-                        rootMap.remove(key)
-                    }
-                }
+                // the flat key of the removed property, those below it and 
its indexed aliases go with it;
+                // the flat keys of its siblings stay
+                String removedKey = path ? "${path}.${sourceKey}".toString() : 
sourceKey
+                removeKeysBelow(rootMap, removedKey, ['.', '['])
+                rootMap.remove(removedKey)
                 targetMap.remove(sourceKey)
             } else {
+                String flatKey = path ? "${path}.${sourceKey}".toString() : 
sourceKey
                 if (path) {
-                    rootMap.put("${path}.${sourceKey}".toString(), newValue)
+                    mergeMapEntry(rootMap, flatKey, newValue)
                 }
                 mergeMapEntry(targetMap, sourceKey, newValue)
+                if (replacedBy(currentValue, newValue)) {
+                    // the element keys of the container the value replaces go 
with it; the flat keys of the
+                    // entries of a block stay, as they always have
+                    removeKeysBelow(rootMap, flatKey, ['['])
+                }
+                writeElements(rootMap, flatKey, newValue)
+            }
+        }
+    }
+
+    /**
+     * Writes the element keys of a list, {@code a.rows[0]} and, for an 
element that is a map, {@code a.rows[0].name},
+     * as the indexed keys of a configuration file write them, so that a list 
is read alike however it was written.
+     * A map that is not a block of this configuration, an element of a list 
or a value an indexed key wrote, has
+     * its entries written the same way; a block writes its own flat keys as 
it is merged.
+     */
+    private void writeElements(NavigableMap rootMap, String flatKey, Object 
value) {
+        if (value instanceof List) {
+            int index = 0
+            for (Object element in (List) value) {

Review Comment:
   Fixed in 7e9b4c22d0. The key `app.names[0]` held the element as it was when 
the list was written, so a `set`, `add` or `remove` on the list left it behind, 
and `other.merge(map, true)` wrote the old element back into the list through 
`mergeIndexedEntry`; the same for an entry of an element map set in place, and 
for a list written by indexed keys. Nothing is held per element now: an indexed 
key is read through the container held under the name before its first 
subscript and the elements the subscripts and names after it step through, so 
`get`, `containsKey` and `getProperty` answer from the list as it is, 
`toProperties()` and `toFlatConfig()` write the elements from the list, and a 
map merged into another carries its lists and no element keys, so it writes 
nothing into them. `NavigableMapPropertySource` reads an element the same way, 
so `environment.getProperty('app.names[0]')` follows the list too; its property 
names are still those of the elements the lists held when it was made.
  The code that wrote and removed element keys goes. `keySet()` no longer lists 
a key per element, and the bracket spelling of a map-subscript key, 
`a.mappings[/api/**]`, is no longer in `toProperties()`, which writes 
`a.mappings./api/**` as before.
   
   Pinned in `NavigableMapSpec` with your sequence, `map.app.names = ['one']` 
then `map.app.names[0] = 'two'`, read by the key, by `toProperties()` for the 
list and for the element, and after `other.merge(map, true)` by the other map 
with the list still `['two']`; and over an element set, added and removed and 
an entry of an element map set, added and removed, each read by `get`, 
`containsKey` and `toProperties()` and after a merge into another map. 
`PropertySourcesConfigSpec` reads the same through a config, 
`NavigableMapPropertySourceSpec` through the property source, and 
`GrailsAppGroovyConfigSpec` sets an element of an `application.groovy` list 
through the config of a started `GrailsApp` and reads it back through the 
config and the environment. The probe over the seventeen write paths reports no 
stale or missing element key any more; what remains is the dotted flat key of a 
block's entry that a value replaced, the block rule, and the re-merge of a 
map-subscript container as a blo
 ck with `parseFlatKeys` off, both older than this PR.
   



-- 
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]

Reply via email to