diff --git a/config/src/main/java/com/typesafe/config/impl/ResolveContext.java b/config/src/main/java/com/typesafe/config/impl/ResolveContext.java index 1765dddb..08af2f74 100644 --- a/config/src/main/java/com/typesafe/config/impl/ResolveContext.java +++ b/config/src/main/java/com/typesafe/config/impl/ResolveContext.java @@ -10,7 +10,6 @@ import com.typesafe.config.ConfigException; import com.typesafe.config.ConfigResolveOptions; import com.typesafe.config.impl.AbstractConfigValue.NotPossibleToResolve; import com.typesafe.config.impl.AbstractConfigValue.SelfReferential; -import com.typesafe.config.impl.ResolveReplacer.Undefined; final class ResolveContext { // this is unfortunately mutable so should only be shared among @@ -164,50 +163,31 @@ final class ResolveContext { } else { MemoKey key = restrictedKey != null ? restrictedKey : fullKey; - AbstractConfigValue replacement; - boolean forceUndefined = false; - try { - replacement = source.replacement(key); - } catch (Undefined e) { - replacement = original; - forceUndefined = true; - } + AbstractConfigValue resolved = source.resolveCheckingReplacement(this, key); - if (replacement != original) { - // start over, checking if replacement was memoized - return resolve(replacement); + if (resolved == null || resolved.resolveStatus() == ResolveStatus.RESOLVED) { + // if the resolved object is fully resolved by resolving + // only the restrictToChildOrNull, then it can be cached + // under fullKey since the child we were restricted to + // turned out to be the only unresolved thing. + memos.put(fullKey, resolved); } else { - AbstractConfigValue resolved; - - if (forceUndefined) - resolved = null; - else - resolved = original.resolveSubstitutions(this); - - if (resolved == null || resolved.resolveStatus() == ResolveStatus.RESOLVED) { - // if the resolved object is fully resolved by resolving - // only the restrictToChildOrNull, then it can be cached - // under fullKey since the child we were restricted to - // turned out to be the only unresolved thing. - memos.put(fullKey, resolved); - } else { - // if we have an unresolved object then either we did a - // partial resolve restricted to a certain child, or it's - // a bug. - if (isRestrictedToChild()) { - if (restrictedKey == null) { - throw new ConfigException.BugOrBroken( - "restrictedKey should not be null here"); - } - memos.put(restrictedKey, resolved); - } else { + // if we have an unresolved object then either we did a + // partial resolve restricted to a certain child, or it's + // a bug. + if (isRestrictedToChild()) { + if (restrictedKey == null) { throw new ConfigException.BugOrBroken( - "resolveSubstitutions() did not give us a resolved object"); + "restrictedKey should not be null here"); } + memos.put(restrictedKey, resolved); + } else { + throw new ConfigException.BugOrBroken( + "resolveSubstitutions() did not give us a resolved object"); } - - return resolved; } + + return resolved; } } diff --git a/config/src/main/java/com/typesafe/config/impl/ResolveSource.java b/config/src/main/java/com/typesafe/config/impl/ResolveSource.java index bdb8d96b..c9df7a92 100644 --- a/config/src/main/java/com/typesafe/config/impl/ResolveSource.java +++ b/config/src/main/java/com/typesafe/config/impl/ResolveSource.java @@ -91,11 +91,43 @@ final class ResolveSource { stack.removeFirst(); } - AbstractConfigValue replacement(MemoKey key) throws Undefined { + private AbstractConfigValue replacement(MemoKey key) throws Undefined { LinkedList<ResolveReplacer> stack = replacements.get(new MemoKey(key.value(), null)); if (stack == null || stack.isEmpty()) return key.value(); else return stack.peek().replace(); } + + /** + * Conceptually, this is key.value().resolveSubstitutions() but using the + * replacement for key.value() if any. + */ + AbstractConfigValue resolveCheckingReplacement(ResolveContext context, MemoKey key) + throws NotPossibleToResolve { + AbstractConfigValue original = key.value(); + + AbstractConfigValue replacement; + boolean forceUndefined = false; + try { + replacement = replacement(key); + } catch (Undefined e) { + replacement = original; + forceUndefined = true; + } + + if (replacement != original) { + // start over, checking if replacement was memoized + return context.resolve(replacement); + } else { + AbstractConfigValue resolved; + + if (forceUndefined) + resolved = null; + else + resolved = original.resolveSubstitutions(context); + + return resolved; + } + } }