mirror of
https://github.com/lightbend/config.git
synced 2025-02-23 17:50:30 +08:00
combine three resolveSubstitutions() parameters into ResolveContext
This makes it easier to mess with the parameters needed without changing every resolveSubstitutions() all over the place. Really the SubstitutionResolver and ResolveContext should maybe be merged, but keeping this patch more incremental.
This commit is contained in:
parent
6de4a991d4
commit
d9c9adc39f
@ -6,16 +6,13 @@ package com.typesafe.config.impl;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import com.typesafe.config.ConfigException;
|
import com.typesafe.config.ConfigException;
|
||||||
import com.typesafe.config.ConfigMergeable;
|
import com.typesafe.config.ConfigMergeable;
|
||||||
import com.typesafe.config.ConfigObject;
|
import com.typesafe.config.ConfigObject;
|
||||||
import com.typesafe.config.ConfigOrigin;
|
import com.typesafe.config.ConfigOrigin;
|
||||||
import com.typesafe.config.ConfigResolveOptions;
|
|
||||||
import com.typesafe.config.ConfigValue;
|
import com.typesafe.config.ConfigValue;
|
||||||
import com.typesafe.config.ConfigValueType;
|
import com.typesafe.config.ConfigValueType;
|
||||||
|
|
||||||
@ -92,9 +89,8 @@ abstract class AbstractConfigObject extends AbstractConfigValue implements
|
|||||||
* @throws NotPossibleToResolve
|
* @throws NotPossibleToResolve
|
||||||
*/
|
*/
|
||||||
protected AbstractConfigValue peekPath(Path path, SubstitutionResolver resolver,
|
protected AbstractConfigValue peekPath(Path path, SubstitutionResolver resolver,
|
||||||
Set<MemoKey> traversed, ConfigResolveOptions options)
|
ResolveContext context) throws NotPossibleToResolve, NeedsFullResolve {
|
||||||
throws NotPossibleToResolve, NeedsFullResolve {
|
return peekPath(this, path, resolver, context);
|
||||||
return peekPath(this, path, resolver, traversed, options);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -103,7 +99,7 @@ abstract class AbstractConfigObject extends AbstractConfigValue implements
|
|||||||
*/
|
*/
|
||||||
AbstractConfigValue peekPathWithExternalExceptions(Path path) {
|
AbstractConfigValue peekPathWithExternalExceptions(Path path) {
|
||||||
try {
|
try {
|
||||||
return peekPath(this, path, null, Collections.<MemoKey> emptySet(), null);
|
return peekPath(this, path, null, null);
|
||||||
} catch (NotPossibleToResolve e) {
|
} catch (NotPossibleToResolve e) {
|
||||||
throw e.exportException(origin(), path.render());
|
throw e.exportException(origin(), path.render());
|
||||||
} catch (NeedsFullResolve e) {
|
} catch (NeedsFullResolve e) {
|
||||||
@ -116,16 +112,14 @@ abstract class AbstractConfigObject extends AbstractConfigValue implements
|
|||||||
// child being peeked, but NOT the child itself. Caller has to resolve
|
// child being peeked, but NOT the child itself. Caller has to resolve
|
||||||
// the child itself if needed.
|
// the child itself if needed.
|
||||||
private static AbstractConfigValue peekPath(AbstractConfigObject self, Path path,
|
private static AbstractConfigValue peekPath(AbstractConfigObject self, Path path,
|
||||||
SubstitutionResolver resolver, Set<MemoKey> traversed, ConfigResolveOptions options)
|
SubstitutionResolver resolver, ResolveContext context)
|
||||||
throws NotPossibleToResolve, NeedsFullResolve {
|
throws NotPossibleToResolve, NeedsFullResolve {
|
||||||
if (resolver != null) {
|
if (resolver != null) {
|
||||||
// walk down through the path resolving only things along that path,
|
// walk down through the path resolving only things along that path,
|
||||||
// and then recursively call ourselves with no resolver.
|
// and then recursively call ourselves with no resolver.
|
||||||
AbstractConfigValue partiallyResolved = resolver
|
AbstractConfigValue partiallyResolved = resolver.resolve(self, context.restrict(path));
|
||||||
.resolve(self, traversed, options, path);
|
|
||||||
if (partiallyResolved instanceof AbstractConfigObject) {
|
if (partiallyResolved instanceof AbstractConfigObject) {
|
||||||
return peekPath((AbstractConfigObject) partiallyResolved, path, null,
|
return peekPath((AbstractConfigObject) partiallyResolved, path, null, null);
|
||||||
traversed, null);
|
|
||||||
} else {
|
} else {
|
||||||
throw new ConfigException.BugOrBroken("resolved object to non-object " + self
|
throw new ConfigException.BugOrBroken("resolved object to non-object " + self
|
||||||
+ " to " + partiallyResolved);
|
+ " to " + partiallyResolved);
|
||||||
@ -140,8 +134,7 @@ abstract class AbstractConfigObject extends AbstractConfigValue implements
|
|||||||
return v;
|
return v;
|
||||||
} else {
|
} else {
|
||||||
if (v instanceof AbstractConfigObject) {
|
if (v instanceof AbstractConfigObject) {
|
||||||
return peekPath((AbstractConfigObject) v, next, null,
|
return peekPath((AbstractConfigObject) v, next, null, null);
|
||||||
Collections.<MemoKey> emptySet(), null);
|
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -223,9 +216,8 @@ abstract class AbstractConfigObject extends AbstractConfigValue implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
abstract AbstractConfigObject resolveSubstitutions(final SubstitutionResolver resolver,
|
abstract AbstractConfigObject resolveSubstitutions(SubstitutionResolver resolver,
|
||||||
Set<MemoKey> traversed, ConfigResolveOptions options, Path restrictToChildOrNull)
|
ResolveContext context) throws NotPossibleToResolve, NeedsFullResolve;
|
||||||
throws NotPossibleToResolve, NeedsFullResolve;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
abstract AbstractConfigObject relativized(final Path prefix);
|
abstract AbstractConfigObject relativized(final Path prefix);
|
||||||
|
@ -4,12 +4,10 @@
|
|||||||
package com.typesafe.config.impl;
|
package com.typesafe.config.impl;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import com.typesafe.config.ConfigException;
|
import com.typesafe.config.ConfigException;
|
||||||
import com.typesafe.config.ConfigMergeable;
|
import com.typesafe.config.ConfigMergeable;
|
||||||
import com.typesafe.config.ConfigOrigin;
|
import com.typesafe.config.ConfigOrigin;
|
||||||
import com.typesafe.config.ConfigResolveOptions;
|
|
||||||
import com.typesafe.config.ConfigValue;
|
import com.typesafe.config.ConfigValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -102,17 +100,12 @@ abstract class AbstractConfigValue implements ConfigValue, MergeableValue, Seria
|
|||||||
*
|
*
|
||||||
* @param resolver
|
* @param resolver
|
||||||
* the resolver doing the resolving
|
* the resolver doing the resolving
|
||||||
* @param traversed
|
* @param context
|
||||||
* objects which have already been visited, will include this one
|
* state of the current resolve
|
||||||
* @param options
|
|
||||||
* whether to look at system props and env vars
|
|
||||||
* @param restrictToChildOrNull
|
|
||||||
* if non-null, only recurse into this child path
|
|
||||||
* @return a new value if there were changes, or this if no changes
|
* @return a new value if there were changes, or this if no changes
|
||||||
*/
|
*/
|
||||||
AbstractConfigValue resolveSubstitutions(SubstitutionResolver resolver, Set<MemoKey> traversed,
|
AbstractConfigValue resolveSubstitutions(SubstitutionResolver resolver, ResolveContext context)
|
||||||
ConfigResolveOptions options, Path restrictToChildOrNull) throws NotPossibleToResolve,
|
throws NotPossibleToResolve, NeedsFullResolve {
|
||||||
NeedsFullResolve {
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,11 +8,9 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import com.typesafe.config.ConfigException;
|
import com.typesafe.config.ConfigException;
|
||||||
import com.typesafe.config.ConfigOrigin;
|
import com.typesafe.config.ConfigOrigin;
|
||||||
import com.typesafe.config.ConfigResolveOptions;
|
|
||||||
import com.typesafe.config.ConfigValueType;
|
import com.typesafe.config.ConfigValueType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -65,16 +63,15 @@ final class ConfigDelayedMerge extends AbstractConfigValue implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
AbstractConfigValue resolveSubstitutions(SubstitutionResolver resolver, Set<MemoKey> traversed,
|
AbstractConfigValue resolveSubstitutions(SubstitutionResolver resolver, ResolveContext context)
|
||||||
ConfigResolveOptions options, Path restrictToChildOrNull) throws NotPossibleToResolve,
|
throws NotPossibleToResolve, NeedsFullResolve {
|
||||||
NeedsFullResolve {
|
return resolveSubstitutions(stack, resolver, context);
|
||||||
return resolveSubstitutions(stack, resolver, traversed, options, restrictToChildOrNull);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// static method also used by ConfigDelayedMergeObject
|
// static method also used by ConfigDelayedMergeObject
|
||||||
static AbstractConfigValue resolveSubstitutions(List<AbstractConfigValue> stack,
|
static AbstractConfigValue resolveSubstitutions(List<AbstractConfigValue> stack,
|
||||||
SubstitutionResolver resolver, Set<MemoKey> traversed, ConfigResolveOptions options,
|
SubstitutionResolver resolver, ResolveContext context) throws NotPossibleToResolve,
|
||||||
Path restrictToChildOrNull) throws NotPossibleToResolve, NeedsFullResolve {
|
NeedsFullResolve {
|
||||||
// to resolve substitutions, we need to recursively resolve
|
// to resolve substitutions, we need to recursively resolve
|
||||||
// the stack of stuff to merge, and merge the stack so
|
// the stack of stuff to merge, and merge the stack so
|
||||||
// we won't be a delayed merge anymore. If restrictToChildOrNull
|
// we won't be a delayed merge anymore. If restrictToChildOrNull
|
||||||
@ -82,8 +79,7 @@ final class ConfigDelayedMerge extends AbstractConfigValue implements
|
|||||||
|
|
||||||
AbstractConfigValue merged = null;
|
AbstractConfigValue merged = null;
|
||||||
for (AbstractConfigValue v : stack) {
|
for (AbstractConfigValue v : stack) {
|
||||||
AbstractConfigValue resolved = resolver.resolve(v, traversed, options,
|
AbstractConfigValue resolved = resolver.resolve(v, context);
|
||||||
restrictToChildOrNull);
|
|
||||||
if (resolved != null) {
|
if (resolved != null) {
|
||||||
if (merged == null)
|
if (merged == null)
|
||||||
merged = resolved;
|
merged = resolved;
|
||||||
|
@ -13,7 +13,6 @@ import java.util.Set;
|
|||||||
import com.typesafe.config.ConfigException;
|
import com.typesafe.config.ConfigException;
|
||||||
import com.typesafe.config.ConfigMergeable;
|
import com.typesafe.config.ConfigMergeable;
|
||||||
import com.typesafe.config.ConfigOrigin;
|
import com.typesafe.config.ConfigOrigin;
|
||||||
import com.typesafe.config.ConfigResolveOptions;
|
|
||||||
import com.typesafe.config.ConfigValue;
|
import com.typesafe.config.ConfigValue;
|
||||||
|
|
||||||
// This is just like ConfigDelayedMerge except we know statically
|
// This is just like ConfigDelayedMerge except we know statically
|
||||||
@ -61,11 +60,10 @@ final class ConfigDelayedMergeObject extends AbstractConfigObject implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
AbstractConfigObject resolveSubstitutions(SubstitutionResolver resolver,
|
AbstractConfigObject resolveSubstitutions(SubstitutionResolver resolver, ResolveContext context)
|
||||||
Set<MemoKey> traversed, ConfigResolveOptions options, Path restrictToChildOrNull)
|
|
||||||
throws NotPossibleToResolve, NeedsFullResolve {
|
throws NotPossibleToResolve, NeedsFullResolve {
|
||||||
AbstractConfigValue merged = ConfigDelayedMerge.resolveSubstitutions(stack, resolver,
|
AbstractConfigValue merged = ConfigDelayedMerge.resolveSubstitutions(stack, resolver,
|
||||||
traversed, options, restrictToChildOrNull);
|
context);
|
||||||
if (merged instanceof AbstractConfigObject) {
|
if (merged instanceof AbstractConfigObject) {
|
||||||
return (AbstractConfigObject) merged;
|
return (AbstractConfigObject) merged;
|
||||||
} else {
|
} else {
|
||||||
|
@ -8,11 +8,9 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import com.typesafe.config.ConfigException;
|
import com.typesafe.config.ConfigException;
|
||||||
import com.typesafe.config.ConfigOrigin;
|
import com.typesafe.config.ConfigOrigin;
|
||||||
import com.typesafe.config.ConfigResolveOptions;
|
|
||||||
import com.typesafe.config.ConfigValue;
|
import com.typesafe.config.ConfigValue;
|
||||||
import com.typesafe.config.ConfigValueType;
|
import com.typesafe.config.ConfigValueType;
|
||||||
|
|
||||||
@ -136,30 +134,25 @@ final class ConfigSubstitution extends AbstractConfigValue implements
|
|||||||
|
|
||||||
private static AbstractConfigValue findInObject(AbstractConfigObject root,
|
private static AbstractConfigValue findInObject(AbstractConfigObject root,
|
||||||
SubstitutionResolver resolver, /* null if we should not have refs */
|
SubstitutionResolver resolver, /* null if we should not have refs */
|
||||||
Path subst, Set<MemoKey> traversed, ConfigResolveOptions options)
|
Path subst, ResolveContext context)
|
||||||
throws NotPossibleToResolve, NeedsFullResolve {
|
throws NotPossibleToResolve, NeedsFullResolve {
|
||||||
|
|
||||||
AbstractConfigValue result = root.peekPath(subst, resolver, traversed, options);
|
AbstractConfigValue result = root.peekPath(subst, resolver, context);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AbstractConfigValue resolve(SubstitutionResolver resolver,
|
private AbstractConfigValue resolve(SubstitutionResolver resolver,
|
||||||
SubstitutionExpression subst, Set<MemoKey> traversed, ConfigResolveOptions options,
|
SubstitutionExpression subst, ResolveContext context) throws NotPossibleToResolve,
|
||||||
Path restrictToChildOrNull) throws NotPossibleToResolve,
|
|
||||||
NeedsFullResolve {
|
NeedsFullResolve {
|
||||||
MemoKey key = new MemoKey(this, restrictToChildOrNull);
|
context.traverse(this, subst.path());
|
||||||
if (traversed.contains(key))
|
|
||||||
throw new SelfReferential(origin(), subst.path().render());
|
|
||||||
|
|
||||||
traversed.add(key);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// First we look up the full path, which means relative to the
|
// First we look up the full path, which means relative to the
|
||||||
// included file if we were not a root file
|
// included file if we were not a root file
|
||||||
AbstractConfigValue result = findInObject(resolver.root(), resolver, subst.path(),
|
AbstractConfigValue result = findInObject(resolver.root(), resolver, subst.path(),
|
||||||
traversed, options);
|
context);
|
||||||
|
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
// Then we want to check relative to the root file. We don't
|
// Then we want to check relative to the root file. We don't
|
||||||
@ -169,28 +162,28 @@ final class ConfigSubstitution extends AbstractConfigValue implements
|
|||||||
Path unprefixed = subst.path().subPath(prefixLength);
|
Path unprefixed = subst.path().subPath(prefixLength);
|
||||||
|
|
||||||
if (result == null && prefixLength > 0) {
|
if (result == null && prefixLength > 0) {
|
||||||
result = findInObject(resolver.root(), resolver, unprefixed, traversed, options);
|
result = findInObject(resolver.root(), resolver, unprefixed, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == null && options.getUseSystemEnvironment()) {
|
if (result == null && context.options().getUseSystemEnvironment()) {
|
||||||
result = findInObject(ConfigImpl.envVariablesAsConfigObject(), null,
|
result = findInObject(ConfigImpl.envVariablesAsConfigObject(), null,
|
||||||
unprefixed, traversed, options);
|
unprefixed, context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
result = resolver.resolve(result, traversed, options, restrictToChildOrNull);
|
result = resolver.resolve(result, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
traversed.remove(key);
|
context.untraverse(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ConfigValue resolve(SubstitutionResolver resolver, Set<MemoKey> traversed,
|
private ConfigValue resolve(SubstitutionResolver resolver, ResolveContext context)
|
||||||
ConfigResolveOptions options, Path restrictToChildOrNull) throws NotPossibleToResolve {
|
throws NotPossibleToResolve {
|
||||||
if (pieces.size() > 1) {
|
if (pieces.size() > 1) {
|
||||||
// need to concat everything into a string
|
// need to concat everything into a string
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
@ -202,8 +195,8 @@ final class ConfigSubstitution extends AbstractConfigValue implements
|
|||||||
ConfigValue v;
|
ConfigValue v;
|
||||||
try {
|
try {
|
||||||
// to concat into a string we have to do a full resolve,
|
// to concat into a string we have to do a full resolve,
|
||||||
// so don't pass along restrictToChildOrNull
|
// so unrestrict the context
|
||||||
v = resolve(resolver, exp, traversed, options, null);
|
v = resolve(resolver, exp, context.unrestricted());
|
||||||
} catch (NeedsFullResolve e) {
|
} catch (NeedsFullResolve e) {
|
||||||
throw new NotPossibleToResolve(null, exp.path().render(),
|
throw new NotPossibleToResolve(null, exp.path().render(),
|
||||||
"Some kind of loop or interdependency prevents resolving " + exp, e);
|
"Some kind of loop or interdependency prevents resolving " + exp, e);
|
||||||
@ -237,7 +230,7 @@ final class ConfigSubstitution extends AbstractConfigValue implements
|
|||||||
SubstitutionExpression exp = (SubstitutionExpression) pieces.get(0);
|
SubstitutionExpression exp = (SubstitutionExpression) pieces.get(0);
|
||||||
ConfigValue v;
|
ConfigValue v;
|
||||||
try {
|
try {
|
||||||
v = resolve(resolver, exp, traversed, options, restrictToChildOrNull);
|
v = resolve(resolver, exp, context);
|
||||||
} catch (NeedsFullResolve e) {
|
} catch (NeedsFullResolve e) {
|
||||||
throw new NotPossibleToResolve(null, exp.path().render(),
|
throw new NotPossibleToResolve(null, exp.path().render(),
|
||||||
"Some kind of loop or interdependency prevents resolving " + exp, e);
|
"Some kind of loop or interdependency prevents resolving " + exp, e);
|
||||||
@ -250,10 +243,9 @@ final class ConfigSubstitution extends AbstractConfigValue implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
AbstractConfigValue resolveSubstitutions(SubstitutionResolver resolver, Set<MemoKey> traversed,
|
AbstractConfigValue resolveSubstitutions(SubstitutionResolver resolver, ResolveContext context)
|
||||||
ConfigResolveOptions options, Path restrictToChildOrNull) throws NotPossibleToResolve {
|
throws NotPossibleToResolve {
|
||||||
AbstractConfigValue resolved = (AbstractConfigValue) resolve(resolver, traversed, options,
|
AbstractConfigValue resolved = (AbstractConfigValue) resolve(resolver, context);
|
||||||
restrictToChildOrNull);
|
|
||||||
return resolved;
|
return resolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,67 @@
|
|||||||
|
package com.typesafe.config.impl;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
|
||||||
|
import com.typesafe.config.ConfigException;
|
||||||
|
import com.typesafe.config.ConfigResolveOptions;
|
||||||
|
import com.typesafe.config.impl.AbstractConfigValue.SelfReferential;
|
||||||
|
|
||||||
|
final class ResolveContext {
|
||||||
|
// this set is unfortunately mutable and the user of ResolveContext
|
||||||
|
// has to be sure it's only shared between ResolveContext that
|
||||||
|
// are in the same traversal.
|
||||||
|
final private Set<MemoKey> traversed;
|
||||||
|
final private ConfigResolveOptions options;
|
||||||
|
final private Path restrictToChild; // can be null
|
||||||
|
|
||||||
|
ResolveContext(Set<MemoKey> traversed, ConfigResolveOptions options, Path restrictToChild) {
|
||||||
|
this.traversed = traversed;
|
||||||
|
this.options = options;
|
||||||
|
this.restrictToChild = restrictToChild;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResolveContext(ConfigResolveOptions options, Path restrictToChild) {
|
||||||
|
// LinkedHashSet keeps the traversal order which is at least useful
|
||||||
|
// in error messages if nothing else
|
||||||
|
this(new LinkedHashSet<MemoKey>(), options, restrictToChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
void traverse(ConfigSubstitution value, Path via) throws SelfReferential {
|
||||||
|
MemoKey key = new MemoKey(value, restrictToChild);
|
||||||
|
if (traversed.contains(key))
|
||||||
|
throw new SelfReferential(value.origin(), via.render());
|
||||||
|
|
||||||
|
traversed.add(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void untraverse(ConfigSubstitution value) {
|
||||||
|
MemoKey key = new MemoKey(value, restrictToChild);
|
||||||
|
if (!traversed.remove(key))
|
||||||
|
throw new ConfigException.BugOrBroken(
|
||||||
|
"untraverse() did not find the untraversed substitution " + value);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigResolveOptions options() {
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isRestrictedToChild() {
|
||||||
|
return restrictToChild != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Path restrictToChild() {
|
||||||
|
return restrictToChild;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResolveContext restrict(Path restrictTo) {
|
||||||
|
if (restrictTo == restrictToChild)
|
||||||
|
return this;
|
||||||
|
else
|
||||||
|
return new ResolveContext(traversed, options, restrictTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResolveContext unrestricted() {
|
||||||
|
return restrict(null);
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,6 @@ package com.typesafe.config.impl;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.AbstractMap;
|
import java.util.AbstractMap;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -74,7 +73,7 @@ final class SimpleConfig implements Config, MergeableValue, Serializable {
|
|||||||
Path path = Path.newPath(pathExpression);
|
Path path = Path.newPath(pathExpression);
|
||||||
ConfigValue peeked;
|
ConfigValue peeked;
|
||||||
try {
|
try {
|
||||||
peeked = object.peekPath(path, null, Collections.<MemoKey> emptySet(), null);
|
peeked = object.peekPath(path, null, null);
|
||||||
} catch (NotPossibleToResolve e) {
|
} catch (NotPossibleToResolve e) {
|
||||||
throw e.exportException(origin(), pathExpression);
|
throw e.exportException(origin(), pathExpression);
|
||||||
} catch (NeedsFullResolve e) {
|
} catch (NeedsFullResolve e) {
|
||||||
|
@ -9,12 +9,10 @@ import java.util.Collection;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ListIterator;
|
import java.util.ListIterator;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import com.typesafe.config.ConfigException;
|
import com.typesafe.config.ConfigException;
|
||||||
import com.typesafe.config.ConfigList;
|
import com.typesafe.config.ConfigList;
|
||||||
import com.typesafe.config.ConfigOrigin;
|
import com.typesafe.config.ConfigOrigin;
|
||||||
import com.typesafe.config.ConfigResolveOptions;
|
|
||||||
import com.typesafe.config.ConfigValue;
|
import com.typesafe.config.ConfigValue;
|
||||||
import com.typesafe.config.ConfigValueType;
|
import com.typesafe.config.ConfigValueType;
|
||||||
|
|
||||||
@ -106,13 +104,11 @@ final class SimpleConfigList extends AbstractConfigValue implements ConfigList {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
SimpleConfigList resolveSubstitutions(final SubstitutionResolver resolver,
|
SimpleConfigList resolveSubstitutions(final SubstitutionResolver resolver,
|
||||||
final Set<MemoKey> traversed, final ConfigResolveOptions options,
|
final ResolveContext context) throws NotPossibleToResolve, NeedsFullResolve {
|
||||||
Path restrictToChildOrNull)
|
|
||||||
throws NotPossibleToResolve, NeedsFullResolve {
|
|
||||||
if (resolved)
|
if (resolved)
|
||||||
return this;
|
return this;
|
||||||
|
|
||||||
if (restrictToChildOrNull != null) {
|
if (context.isRestrictedToChild()) {
|
||||||
// if a list restricts to a child path, then it has no child paths,
|
// if a list restricts to a child path, then it has no child paths,
|
||||||
// so nothing to do.
|
// so nothing to do.
|
||||||
return this;
|
return this;
|
||||||
@ -122,7 +118,7 @@ final class SimpleConfigList extends AbstractConfigValue implements ConfigList {
|
|||||||
@Override
|
@Override
|
||||||
public AbstractConfigValue modifyChildMayThrow(String key, AbstractConfigValue v)
|
public AbstractConfigValue modifyChildMayThrow(String key, AbstractConfigValue v)
|
||||||
throws NotPossibleToResolve, NeedsFullResolve {
|
throws NotPossibleToResolve, NeedsFullResolve {
|
||||||
return resolver.resolve(v, traversed, options, null /* restrictToChild */);
|
return resolver.resolve(v, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
}, ResolveStatus.RESOLVED);
|
}, ResolveStatus.RESOLVED);
|
||||||
|
@ -16,7 +16,6 @@ import java.util.Set;
|
|||||||
import com.typesafe.config.ConfigException;
|
import com.typesafe.config.ConfigException;
|
||||||
import com.typesafe.config.ConfigObject;
|
import com.typesafe.config.ConfigObject;
|
||||||
import com.typesafe.config.ConfigOrigin;
|
import com.typesafe.config.ConfigOrigin;
|
||||||
import com.typesafe.config.ConfigResolveOptions;
|
|
||||||
import com.typesafe.config.ConfigValue;
|
import com.typesafe.config.ConfigValue;
|
||||||
|
|
||||||
final class SimpleConfigObject extends AbstractConfigObject {
|
final class SimpleConfigObject extends AbstractConfigObject {
|
||||||
@ -261,9 +260,7 @@ final class SimpleConfigObject extends AbstractConfigObject {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
AbstractConfigObject resolveSubstitutions(final SubstitutionResolver resolver,
|
AbstractConfigObject resolveSubstitutions(final SubstitutionResolver resolver,
|
||||||
final Set<MemoKey> traversed, final ConfigResolveOptions options,
|
final ResolveContext context) throws NotPossibleToResolve, NeedsFullResolve {
|
||||||
final Path restrictToChildOrNull)
|
|
||||||
throws NotPossibleToResolve, NeedsFullResolve {
|
|
||||||
if (resolveStatus() == ResolveStatus.RESOLVED)
|
if (resolveStatus() == ResolveStatus.RESOLVED)
|
||||||
return this;
|
return this;
|
||||||
|
|
||||||
@ -273,11 +270,11 @@ final class SimpleConfigObject extends AbstractConfigObject {
|
|||||||
@Override
|
@Override
|
||||||
public AbstractConfigValue modifyChildMayThrow(String key, AbstractConfigValue v)
|
public AbstractConfigValue modifyChildMayThrow(String key, AbstractConfigValue v)
|
||||||
throws NotPossibleToResolve, NeedsFullResolve {
|
throws NotPossibleToResolve, NeedsFullResolve {
|
||||||
if (restrictToChildOrNull != null) {
|
if (context.isRestrictedToChild()) {
|
||||||
if (key.equals(restrictToChildOrNull.first())) {
|
if (key.equals(context.restrictToChild().first())) {
|
||||||
Path remainder = restrictToChildOrNull.remainder();
|
Path remainder = context.restrictToChild().remainder();
|
||||||
if (remainder != null) {
|
if (remainder != null) {
|
||||||
return resolver.resolve(v, traversed, options, remainder);
|
return resolver.resolve(v, context.restrict(remainder));
|
||||||
} else {
|
} else {
|
||||||
// we don't want to resolve the leaf child.
|
// we don't want to resolve the leaf child.
|
||||||
return v;
|
return v;
|
||||||
@ -288,7 +285,7 @@ final class SimpleConfigObject extends AbstractConfigObject {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// no restrictToChild, resolve everything
|
// no restrictToChild, resolve everything
|
||||||
return resolver.resolve(v, traversed, options, null);
|
return resolver.resolve(v, context.unrestricted());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,9 +4,7 @@
|
|||||||
package com.typesafe.config.impl;
|
package com.typesafe.config.impl;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import com.typesafe.config.ConfigException;
|
import com.typesafe.config.ConfigException;
|
||||||
import com.typesafe.config.ConfigResolveOptions;
|
import com.typesafe.config.ConfigResolveOptions;
|
||||||
@ -29,9 +27,8 @@ final class SubstitutionResolver {
|
|||||||
this.memos = new HashMap<MemoKey, AbstractConfigValue>();
|
this.memos = new HashMap<MemoKey, AbstractConfigValue>();
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractConfigValue resolve(AbstractConfigValue original, Set<MemoKey> traversed,
|
AbstractConfigValue resolve(AbstractConfigValue original, ResolveContext context)
|
||||||
ConfigResolveOptions options, Path restrictToChildOrNull) throws NotPossibleToResolve,
|
throws NotPossibleToResolve, NeedsFullResolve {
|
||||||
NeedsFullResolve {
|
|
||||||
|
|
||||||
// a fully-resolved (no restrictToChild) object can satisfy a
|
// a fully-resolved (no restrictToChild) object can satisfy a
|
||||||
// request for a restricted object, so always check that first.
|
// request for a restricted object, so always check that first.
|
||||||
@ -43,16 +40,15 @@ final class SubstitutionResolver {
|
|||||||
// but if there was no fully-resolved object cached, we'll only
|
// but if there was no fully-resolved object cached, we'll only
|
||||||
// compute the restrictToChild object so use a more limited
|
// compute the restrictToChild object so use a more limited
|
||||||
// memo key
|
// memo key
|
||||||
if (cached == null && restrictToChildOrNull != null) {
|
if (cached == null && context.isRestrictedToChild()) {
|
||||||
restrictedKey = new MemoKey(original, restrictToChildOrNull);
|
restrictedKey = new MemoKey(original, context.restrictToChild());
|
||||||
cached = memos.get(restrictedKey);
|
cached = memos.get(restrictedKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cached != null) {
|
if (cached != null) {
|
||||||
return cached;
|
return cached;
|
||||||
} else {
|
} else {
|
||||||
AbstractConfigValue resolved = original.resolveSubstitutions(this, traversed, options,
|
AbstractConfigValue resolved = original.resolveSubstitutions(this, context);
|
||||||
restrictToChildOrNull);
|
|
||||||
|
|
||||||
if (resolved == null || resolved.resolveStatus() == ResolveStatus.RESOLVED) {
|
if (resolved == null || resolved.resolveStatus() == ResolveStatus.RESOLVED) {
|
||||||
// if the resolved object is fully resolved by resolving
|
// if the resolved object is fully resolved by resolving
|
||||||
@ -64,15 +60,15 @@ final class SubstitutionResolver {
|
|||||||
// if we have an unresolved object then either we did a
|
// if we have an unresolved object then either we did a
|
||||||
// partial resolve restricted to a certain child, or it's
|
// partial resolve restricted to a certain child, or it's
|
||||||
// a bug.
|
// a bug.
|
||||||
if (restrictToChildOrNull == null) {
|
if (context.isRestrictedToChild()) {
|
||||||
throw new ConfigException.BugOrBroken(
|
|
||||||
"resolveSubstitutions() did not give us a resolved object");
|
|
||||||
} else {
|
|
||||||
if (restrictedKey == null) {
|
if (restrictedKey == null) {
|
||||||
throw new ConfigException.BugOrBroken(
|
throw new ConfigException.BugOrBroken(
|
||||||
"restrictedKey should not be null here");
|
"restrictedKey should not be null here");
|
||||||
}
|
}
|
||||||
memos.put(restrictedKey, resolved);
|
memos.put(restrictedKey, resolved);
|
||||||
|
} else {
|
||||||
|
throw new ConfigException.BugOrBroken(
|
||||||
|
"resolveSubstitutions() did not give us a resolved object");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,25 +80,19 @@ final class SubstitutionResolver {
|
|||||||
return this.root;
|
return this.root;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Set<MemoKey> newTraversedSet() {
|
|
||||||
// using LinkedHashSet just to show the order of traversal
|
|
||||||
// in error messages.
|
|
||||||
return new LinkedHashSet<MemoKey>();
|
|
||||||
}
|
|
||||||
|
|
||||||
static AbstractConfigValue resolve(AbstractConfigValue value, AbstractConfigObject root,
|
static AbstractConfigValue resolve(AbstractConfigValue value, AbstractConfigObject root,
|
||||||
ConfigResolveOptions options, Path restrictToChildOrNull) throws NotPossibleToResolve,
|
ConfigResolveOptions options, Path restrictToChildOrNull) throws NotPossibleToResolve,
|
||||||
NeedsFullResolve {
|
NeedsFullResolve {
|
||||||
SubstitutionResolver resolver = new SubstitutionResolver(root);
|
SubstitutionResolver resolver = new SubstitutionResolver(root);
|
||||||
|
|
||||||
return resolver.resolve(value, newTraversedSet(), options, restrictToChildOrNull);
|
return resolver.resolve(value, new ResolveContext(options, restrictToChildOrNull));
|
||||||
}
|
}
|
||||||
|
|
||||||
static AbstractConfigValue resolveWithExternalExceptions(AbstractConfigValue value,
|
static AbstractConfigValue resolveWithExternalExceptions(AbstractConfigValue value,
|
||||||
AbstractConfigObject root, ConfigResolveOptions options) {
|
AbstractConfigObject root, ConfigResolveOptions options) {
|
||||||
SubstitutionResolver resolver = new SubstitutionResolver(root);
|
SubstitutionResolver resolver = new SubstitutionResolver(root);
|
||||||
try {
|
try {
|
||||||
return resolver.resolve(value, newTraversedSet(), options, null /* restrictToChild */);
|
return resolver.resolve(value, new ResolveContext(options, null /* restrictToChild */));
|
||||||
} catch (NotPossibleToResolve e) {
|
} catch (NotPossibleToResolve e) {
|
||||||
throw e.exportException(value.origin(), null);
|
throw e.exportException(value.origin(), null);
|
||||||
} catch (NeedsFullResolve e) {
|
} catch (NeedsFullResolve e) {
|
||||||
|
Loading…
Reference in New Issue
Block a user