jdaugherty commented on code in PR #16798:
URL: https://github.com/apache/grails-core/pull/16798#discussion_r4424614541
##########
grails-core/src/main/groovy/org/grails/config/NavigableMapConfig.java:
##########
@@ -56,13 +57,93 @@ public abstract class NavigableMapConfig implements Config {
protected ClassLoader classLoader =
Thread.currentThread().getContextClassLoader();
protected ConfigurableConversionService conversionService = new
DefaultConversionService();
protected NavigableMap configMap = new NavigableMap() {
+
+ /**
+ * A value resolved for a dotted key, which the merge writes twice in
a row: under the whole key and then,
+ * in the nested map, under its last part. The second write takes the
value the first one resolved.
+ */
+ private Object pendingSource;
+ private Object pendingResolved;
+
+ /**
+ * Resolves the placeholders in a list, which is stored as it is, and
in a value written under an indexed key,
+ * {@code rows[0]} or {@code rows[0].url}, which is written into its
list or map without the hook below.
+ */
+ @Override
+ protected void mergeMapEntry(NavigableMap rootMap, String path,
NavigableMap targetMap, String sourceKey,
+ Object sourceValue, boolean parseFlatKeys, boolean
isNestedSet) {
+ Object value = pendingSource != null && pendingSource ==
sourceValue ? pendingResolved : resolvedBeforeMerge(sourceKey, sourceValue);
+ pendingSource = null;
+ pendingResolved = null;
+ if (value != sourceValue && parseFlatKeys &&
sourceKey.split("\\.").length > 1) {
+ pendingSource = sourceValue;
+ pendingResolved = value;
+ }
+ super.mergeMapEntry(rootMap, path, targetMap, sourceKey, value,
parseFlatKeys, isNestedSet);
+ }
+
@Override
protected Object mergeMapEntry(NavigableMap targetMap, String
sourceKey, Object newValue) {
if (newValue instanceof CharSequence) {
newValue = resolvePlaceholders(newValue.toString());
}
return super.mergeMapEntry(targetMap, sourceKey, newValue);
}
+
+ private Object resolvedBeforeMerge(String sourceKey, Object value) {
+ if (value instanceof List) {
Review Comment:
Fixed in f2fa67765c. The values of an ordinary property source are resolved
once, by `processAndEvaluate()`, and the merge now writes them as they are.
With `host=secret`, `\${host}` reads as `${host}` as a value, in a list and
under an indexed key, as the `Environment` reads it.
A plain string from such a source was already resolved twice on 7.0.x and
read `secret`; it now reads `${host}` too. A `ConfigObject` value, which
skipped `processAndEvaluate()` and was resolved by the merge, now goes through
`processAndEvaluate()` like the others, so its placeholders are still resolved.
Covered by `a value of an ordinary property source is resolved once, so an
escaped placeholder is kept as text, as the environment keeps it`. The
configuration guide's YAML page now says that an escaped placeholder is kept as
text.
##########
grails-core/src/main/groovy/org/grails/config/NavigableMapConfig.java:
##########
@@ -56,13 +57,93 @@ public abstract class NavigableMapConfig implements Config {
protected ClassLoader classLoader =
Thread.currentThread().getContextClassLoader();
protected ConfigurableConversionService conversionService = new
DefaultConversionService();
protected NavigableMap configMap = new NavigableMap() {
+
+ /**
+ * A value resolved for a dotted key, which the merge writes twice in
a row: under the whole key and then,
+ * in the nested map, under its last part. The second write takes the
value the first one resolved.
+ */
+ private Object pendingSource;
+ private Object pendingResolved;
+
+ /**
+ * Resolves the placeholders in a list, which is stored as it is, and
in a value written under an indexed key,
+ * {@code rows[0]} or {@code rows[0].url}, which is written into its
list or map without the hook below.
+ */
+ @Override
+ protected void mergeMapEntry(NavigableMap rootMap, String path,
NavigableMap targetMap, String sourceKey,
+ Object sourceValue, boolean parseFlatKeys, boolean
isNestedSet) {
+ Object value = pendingSource != null && pendingSource ==
sourceValue ? pendingResolved : resolvedBeforeMerge(sourceKey, sourceValue);
Review Comment:
Fixed in f2fa67765c. A merge now resolves a text once under the full name of
its entry, such as `app.hosts[0]`, `app.rows[0].url` or `app.rows[0].tags[0]`,
whichever key writes it: the list in the nested map, the list under the flat
key, or the indexed key. This replaces the pending value, so it also holds when
flat keys are off.
`a placeholder in a list element of application.yml is resolved once, alike
for every read` loads `application.yml` through Grails' YAML loader, beside a
property source that answers a new value on every read. The source is read
three times, once per element, and `config['app.hosts[0]']`,
`getProperty('app.hosts[0]')`, the whole list, `navigate` and `toProperties()`
agree for each element. The previous head read it 13 times.
--
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]