mirror of
https://github.com/lightbend/config.git
synced 2025-03-23 07:40:25 +08:00
split 'ResolveSource' from SubstitutionResolver and ConfigSubstitution.
this is part of a plan to remove SubstitutionResolver (moving the memoized hash to ResolveContext) and to move the "replacements" functionality to ResolveSource. Should be clearer.
This commit is contained in:
parent
e438dfc8c2
commit
d6b27c839a
@ -133,54 +133,7 @@ final class ConfigSubstitution extends AbstractConfigValue implements
|
||||
return pieces;
|
||||
}
|
||||
|
||||
/** resolver is null if we should not have refs */
|
||||
private AbstractConfigValue findInObject(final AbstractConfigObject root,
|
||||
final SubstitutionResolver resolver, final SubstitutionExpression subst,
|
||||
final ResolveContext context) throws NotPossibleToResolve {
|
||||
return context.traversing(this, subst, new ResolveContext.Resolver() {
|
||||
@Override
|
||||
public AbstractConfigValue call() throws NotPossibleToResolve {
|
||||
return root.peekPath(subst.path(), resolver, context);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private AbstractConfigValue resolve(final SubstitutionResolver resolver,
|
||||
final SubstitutionExpression subst, final ResolveContext context)
|
||||
throws NotPossibleToResolve {
|
||||
// First we look up the full path, which means relative to the
|
||||
// included file if we were not a root file
|
||||
AbstractConfigValue result = findInObject(resolver.root(), resolver, subst, context);
|
||||
|
||||
if (result == null) {
|
||||
// Then we want to check relative to the root file. We don't
|
||||
// want the prefix we were included at to be used when looking
|
||||
// up env variables either.
|
||||
SubstitutionExpression unprefixed = subst
|
||||
.changePath(subst.path().subPath(prefixLength));
|
||||
|
||||
if (result == null && prefixLength > 0) {
|
||||
result = findInObject(resolver.root(), resolver, unprefixed, context);
|
||||
}
|
||||
|
||||
if (result == null && context.options().getUseSystemEnvironment()) {
|
||||
result = findInObject(ConfigImpl.envVariablesAsConfigObject(), null, unprefixed,
|
||||
context);
|
||||
}
|
||||
}
|
||||
|
||||
if (result != null) {
|
||||
final AbstractConfigValue unresolved = result;
|
||||
result = context.traversing(this, subst, new ResolveContext.Resolver() {
|
||||
@Override
|
||||
public AbstractConfigValue call() throws NotPossibleToResolve {
|
||||
return resolver.resolve(unresolved, context);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static ResolveReplacer undefinedReplacer = new ResolveReplacer() {
|
||||
@Override
|
||||
@ -201,7 +154,8 @@ final class ConfigSubstitution extends AbstractConfigValue implements
|
||||
|
||||
// to concat into a string we have to do a full resolve,
|
||||
// so unrestrict the context
|
||||
AbstractConfigValue v = resolve(resolver, exp, context.unrestricted());
|
||||
AbstractConfigValue v = context.source().lookupSubst(resolver,
|
||||
context.unrestricted(), this, exp, prefixLength);
|
||||
|
||||
if (v == null) {
|
||||
if (exp.optional()) {
|
||||
@ -233,7 +187,8 @@ final class ConfigSubstitution extends AbstractConfigValue implements
|
||||
"ConfigSubstitution should never contain a single String piece");
|
||||
|
||||
SubstitutionExpression exp = (SubstitutionExpression) pieces.get(0);
|
||||
AbstractConfigValue v = resolve(resolver, exp, context);
|
||||
AbstractConfigValue v = context.source().lookupSubst(resolver, context, this, exp,
|
||||
prefixLength);
|
||||
|
||||
if (v == null && !exp.optional()) {
|
||||
throw new ConfigException.UnresolvedSubstitution(origin(), exp.toString());
|
||||
|
@ -15,6 +15,9 @@ 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
|
||||
// ResolveContext in the same traversal.
|
||||
final private ResolveSource source;
|
||||
// Resolves that we have already begun (for cycle detection).
|
||||
// SubstitutionResolver separately memoizes completed resolves.
|
||||
// this set is unfortunately mutable and the user of ResolveContext
|
||||
@ -30,19 +33,21 @@ final class ResolveContext {
|
||||
// given replacement instead.
|
||||
final private Map<MemoKey, LinkedList<ResolveReplacer>> replacements;
|
||||
|
||||
ResolveContext(LinkedList<Set<MemoKey>> traversedStack, ConfigResolveOptions options,
|
||||
Path restrictToChild,
|
||||
ResolveContext(ResolveSource source, LinkedList<Set<MemoKey>> traversedStack,
|
||||
ConfigResolveOptions options, Path restrictToChild,
|
||||
Map<MemoKey, LinkedList<ResolveReplacer>> replacements) {
|
||||
this.source = source;
|
||||
this.traversedStack = traversedStack;
|
||||
this.options = options;
|
||||
this.restrictToChild = restrictToChild;
|
||||
this.replacements = replacements;
|
||||
}
|
||||
|
||||
ResolveContext(ConfigResolveOptions options, Path restrictToChild) {
|
||||
ResolveContext(AbstractConfigObject root, ConfigResolveOptions options, Path restrictToChild) {
|
||||
// LinkedHashSet keeps the traversal order which is at least useful
|
||||
// in error messages if nothing else
|
||||
this(new LinkedList<Set<MemoKey>>(Collections.singletonList(new LinkedHashSet<MemoKey>())),
|
||||
this(new ResolveSource(root), new LinkedList<Set<MemoKey>>(
|
||||
Collections.singletonList(new LinkedHashSet<MemoKey>())),
|
||||
options, restrictToChild, new HashMap<MemoKey, LinkedList<ResolveReplacer>>());
|
||||
}
|
||||
|
||||
@ -125,6 +130,10 @@ final class ResolveContext {
|
||||
return stack.peek().replace();
|
||||
}
|
||||
|
||||
ResolveSource source() {
|
||||
return source;
|
||||
}
|
||||
|
||||
ConfigResolveOptions options() {
|
||||
return options;
|
||||
}
|
||||
@ -141,7 +150,7 @@ final class ResolveContext {
|
||||
if (restrictTo == restrictToChild)
|
||||
return this;
|
||||
else
|
||||
return new ResolveContext(traversedStack, options, restrictTo, replacements);
|
||||
return new ResolveContext(source, traversedStack, options, restrictTo, replacements);
|
||||
}
|
||||
|
||||
ResolveContext unrestricted() {
|
||||
|
@ -0,0 +1,64 @@
|
||||
package com.typesafe.config.impl;
|
||||
|
||||
import com.typesafe.config.impl.AbstractConfigValue.NotPossibleToResolve;
|
||||
|
||||
/**
|
||||
* This class is the source for values for a substitution like ${foo}.
|
||||
*/
|
||||
final class ResolveSource {
|
||||
final private AbstractConfigObject root;
|
||||
|
||||
ResolveSource(AbstractConfigObject root) {
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
/** resolver is null if we should not have refs */
|
||||
static private AbstractConfigValue findInObject(final AbstractConfigObject obj,
|
||||
final SubstitutionResolver resolver, final ResolveContext context,
|
||||
ConfigSubstitution traversed, final SubstitutionExpression subst)
|
||||
throws NotPossibleToResolve {
|
||||
return context.traversing(traversed, subst, new ResolveContext.Resolver() {
|
||||
@Override
|
||||
public AbstractConfigValue call() throws NotPossibleToResolve {
|
||||
return obj.peekPath(subst.path(), resolver, context);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
AbstractConfigValue lookupSubst(final SubstitutionResolver resolver,
|
||||
final ResolveContext context, ConfigSubstitution traversed,
|
||||
final SubstitutionExpression subst, int prefixLength) throws NotPossibleToResolve {
|
||||
// First we look up the full path, which means relative to the
|
||||
// included file if we were not a root file
|
||||
AbstractConfigValue result = findInObject(root, resolver, context, traversed, subst);
|
||||
|
||||
if (result == null) {
|
||||
// Then we want to check relative to the root file. We don't
|
||||
// want the prefix we were included at to be used when looking
|
||||
// up env variables either.
|
||||
SubstitutionExpression unprefixed = subst
|
||||
.changePath(subst.path().subPath(prefixLength));
|
||||
|
||||
if (result == null && prefixLength > 0) {
|
||||
result = findInObject(root, resolver, context, traversed, unprefixed);
|
||||
}
|
||||
|
||||
if (result == null && context.options().getUseSystemEnvironment()) {
|
||||
result = findInObject(ConfigImpl.envVariablesAsConfigObject(), null, context,
|
||||
traversed, unprefixed);
|
||||
}
|
||||
}
|
||||
|
||||
if (result != null) {
|
||||
final AbstractConfigValue unresolved = result;
|
||||
result = context.traversing(traversed, subst, new ResolveContext.Resolver() {
|
||||
@Override
|
||||
public AbstractConfigValue call() throws NotPossibleToResolve {
|
||||
return resolver.resolve(unresolved, context);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
@ -17,13 +17,11 @@ import com.typesafe.config.impl.ResolveReplacer.Undefined;
|
||||
* of values or whole trees of values as we follow chains of substitutions.
|
||||
*/
|
||||
final class SubstitutionResolver {
|
||||
final private AbstractConfigObject root;
|
||||
// note that we can resolve things to undefined (represented as Java null,
|
||||
// rather than ConfigNull) so this map can have null values.
|
||||
final private Map<MemoKey, AbstractConfigValue> memos;
|
||||
|
||||
SubstitutionResolver(AbstractConfigObject root) {
|
||||
this.root = root;
|
||||
SubstitutionResolver() {
|
||||
this.memos = new HashMap<MemoKey, AbstractConfigValue>();
|
||||
}
|
||||
|
||||
@ -97,22 +95,18 @@ final class SubstitutionResolver {
|
||||
}
|
||||
}
|
||||
|
||||
AbstractConfigObject root() {
|
||||
return this.root;
|
||||
}
|
||||
|
||||
static AbstractConfigValue resolve(AbstractConfigValue value, AbstractConfigObject root,
|
||||
ConfigResolveOptions options, Path restrictToChildOrNull) throws NotPossibleToResolve {
|
||||
SubstitutionResolver resolver = new SubstitutionResolver(root);
|
||||
ResolveContext context = new ResolveContext(options, restrictToChildOrNull);
|
||||
SubstitutionResolver resolver = new SubstitutionResolver();
|
||||
ResolveContext context = new ResolveContext(root, options, restrictToChildOrNull);
|
||||
|
||||
return resolver.resolve(value, context);
|
||||
}
|
||||
|
||||
static AbstractConfigValue resolveWithExternalExceptions(AbstractConfigValue value,
|
||||
AbstractConfigObject root, ConfigResolveOptions options) {
|
||||
SubstitutionResolver resolver = new SubstitutionResolver(root);
|
||||
ResolveContext context = new ResolveContext(options, null /* restrictToChild */);
|
||||
SubstitutionResolver resolver = new SubstitutionResolver();
|
||||
ResolveContext context = new ResolveContext(root, options, null /* restrictToChild */);
|
||||
|
||||
try {
|
||||
return resolver.resolve(value, context);
|
||||
|
Loading…
Reference in New Issue
Block a user