codeconsole commented on code in PR #16772:
URL: https://github.com/apache/grails-core/pull/16772#discussion_r4416033114
##########
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:
Fixed in a1dbcc2e9c, with the condition matrei suggested on this line. A
dotted name the map holds as a key of its own now stays beside the bracketed
one, as well as one the nested maps hold a value at. After `put('a.b.c', 'x')`
and `merge(['a[b.c]': 'x'], true)`, in either order, the export holds both
`a.b.c=x` and `a[b.c]=x`. `a[b.c]` alone still exports only the bracketed name,
since merging it writes no key `a.b.c`. Both orders are rows in the
exact-export table in `ConfigMapSpec`, and both fail at a0ce568a1a. The
`grails-bootstrap` and `grails-core` suites pass.
##########
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)
Review Comment:
Added in 0120ef67d7: the class javadoc now names this case. When a higher
config spells a property in brackets and a lower one dotted, `flatten()` and
`toProperties()` keep the lower value under the dotted name, while
`getProperty` answers the higher one. `:grails-core:javadoc` builds clean.
##########
grails-core/src/test/groovy/org/grails/config/PropertySourcesConfigSpec.groovy:
##########
@@ -184,6 +225,36 @@ class PropertySourcesConfigSpec extends Specification {
counter.readCount() == 1
}
+ void 'a dotted key inside a nested map is exported under its full path and
overwrites no other property'() {
Review Comment:
Done in 8effaa8665. The two features are back where 7.0.x has them, and the
four features of this PR follow the ones 7.0.x already had, so the diff of
`PropertySourcesConfigSpec` only adds.
--
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]