add a ConfigRoot type returned by load()

The point is to only support the resolve() method on the root object.
This commit is contained in:
Havoc Pennington 2011-11-11 22:11:57 -05:00
parent 529b3b1f55
commit 839c588277
8 changed files with 175 additions and 63 deletions

View File

@ -15,7 +15,7 @@ public final class Config {
* configuration for the configuration.
* @return a configuration object
*/
public static ConfigObject load(ConfigConfig configConfig) {
public static ConfigRoot load(ConfigConfig configConfig) {
return ConfigImpl.loadConfig(configConfig);
}
@ -27,11 +27,15 @@ public final class Config {
* path may have periods in it if you like but other punctuation or
* whitespace will probably cause you headaches. Example root paths: "akka",
* "sbt", "jsoup", "heroku", "mongo", etc.
*
* This object will already be resolved (substitutions have already been
* processed).
*
* @param rootPath
* the configuration "domain"
* @return configuration object for the requested root path
*/
public static ConfigObject load(String rootPath) {
public static ConfigRoot load(String rootPath) {
return ConfigImpl.loadConfig(new ConfigConfig(rootPath));
}

View File

@ -0,0 +1,21 @@
package com.typesafe.config;
/**
* A root object. The only special thing about a root object is that you can
* resolve substitutions against it. So it can have a resolve() method that
* doesn't require you to pass in an object to resolve against.
*/
public interface ConfigRoot extends ConfigObject {
/**
* Returns a replacement root object with all substitutions (the
* "${foo.bar}" syntax) resolved. Substitutions are looked up in this root
* object. A configuration value tree must be resolved before you can use
* it.
*
* @return an immutable object with substitutions resolved
*/
ConfigRoot resolve();
@Override
ConfigRoot withFallback(ConfigValue fallback);
}

View File

@ -15,6 +15,7 @@ import com.typesafe.config.ConfigException;
import com.typesafe.config.ConfigList;
import com.typesafe.config.ConfigObject;
import com.typesafe.config.ConfigOrigin;
import com.typesafe.config.ConfigRoot;
import com.typesafe.config.ConfigValue;
import com.typesafe.config.ConfigValueType;
@ -34,6 +35,22 @@ abstract class AbstractConfigObject extends AbstractConfigValue implements
this(origin, ConfigImpl.defaultConfigTransformer());
}
/**
* Returns a version of this object that implements the ConfigRoot
* interface.
*
* @return a config root
*/
protected ConfigRoot asRoot() {
return new RootConfigObject(this);
}
protected static ConfigRoot resolve(ConfigRoot root) {
AbstractConfigValue resolved = SubstitutionResolver.resolve(
(AbstractConfigValue) root, (AbstractConfigObject) root);
return ((AbstractConfigObject) resolved).asRoot();
}
/**
* This looks up the key with no transformation or type conversion of any
* kind, and returns null if the key is not present.

View File

@ -8,11 +8,12 @@ import java.util.Set;
import com.typesafe.config.ConfigException;
import com.typesafe.config.ConfigOrigin;
import com.typesafe.config.ConfigRoot;
import com.typesafe.config.ConfigValue;
// This is just like ConfigDelayedMerge except we know statically
// that it will turn out to be an object.
final class ConfigDelayedMergeObject extends AbstractConfigObject implements
class ConfigDelayedMergeObject extends AbstractConfigObject implements
Unresolved {
final private List<AbstractConfigValue> stack;
@ -29,6 +30,33 @@ final class ConfigDelayedMergeObject extends AbstractConfigObject implements
"created a delayed merge object not guaranteed to be an object");
}
final private static class Root extends ConfigDelayedMergeObject implements
ConfigRoot {
Root(ConfigDelayedMergeObject original) {
super(original.origin(), original.stack);
}
@Override
protected Root asRoot() {
return this;
}
@Override
public ConfigRoot resolve() {
return resolve(this);
}
@Override
public Root withFallback(ConfigValue value) {
return super.withFallback(value).asRoot();
}
}
@Override
protected Root asRoot() {
return new Root(this);
}
@Override
AbstractConfigObject resolveSubstitutions(SubstitutionResolver resolver,
int depth, boolean withFallbacks) {
@ -44,7 +72,7 @@ final class ConfigDelayedMergeObject extends AbstractConfigObject implements
}
@Override
public AbstractConfigObject withFallback(ConfigValue other) {
public ConfigDelayedMergeObject withFallback(ConfigValue other) {
if (other instanceof AbstractConfigObject
|| other instanceof Unresolved) {
// since we are an object, and the fallback could be,

View File

@ -8,10 +8,11 @@ import java.util.Map;
import com.typesafe.config.ConfigConfig;
import com.typesafe.config.ConfigException;
import com.typesafe.config.ConfigObject;
import com.typesafe.config.ConfigRoot;
/** This is public but is only supposed to be used by the "config" package */
public class ConfigImpl {
public static ConfigObject loadConfig(ConfigConfig configConfig) {
public static ConfigRoot loadConfig(ConfigConfig configConfig) {
ConfigTransformer transformer = withExtraTransformer(null);
AbstractConfigObject system = null;
@ -36,10 +37,9 @@ public class ConfigImpl {
AbstractConfigObject merged = AbstractConfigObject.merge(stack);
AbstractConfigValue resolved = SubstitutionResolver.resolve(merged,
merged);
ConfigRoot resolved = merged.asRoot().resolve();
return (AbstractConfigObject) resolved;
return resolved;
}
static ConfigObject getEnvironmentAsConfig() {

View File

@ -0,0 +1,67 @@
package com.typesafe.config.impl;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import com.typesafe.config.ConfigValue;
abstract class DelegatingConfigObject extends AbstractConfigObject {
final private AbstractConfigObject underlying;
DelegatingConfigObject(ConfigTransformer transformer,
AbstractConfigObject underlying) {
super(underlying.origin(), transformer);
this.underlying = underlying;
}
@Override
public boolean containsKey(Object key) {
return underlying.containsKey(key);
}
@Override
public Set<String> keySet() {
return underlying.keySet();
}
@Override
public Map<String, Object> unwrapped() {
return underlying.unwrapped();
}
@Override
protected AbstractConfigValue peek(String key) {
return underlying.peek(key);
}
@Override
public AbstractConfigObject withFallback(ConfigValue value) {
return underlying.withFallback(value);
}
@Override
public boolean containsValue(Object value) {
return underlying.containsValue(value);
}
@Override
public Set<java.util.Map.Entry<String, ConfigValue>> entrySet() {
return underlying.entrySet();
}
@Override
public boolean isEmpty() {
return underlying.isEmpty();
}
@Override
public int size() {
return underlying.size();
}
@Override
public Collection<ConfigValue> values() {
return underlying.values();
}
}

View File

@ -0,0 +1,28 @@
package com.typesafe.config.impl;
import com.typesafe.config.ConfigRoot;
import com.typesafe.config.ConfigValue;
final class RootConfigObject extends DelegatingConfigObject implements
ConfigRoot {
RootConfigObject(AbstractConfigObject underlying) {
super(underlying.transformer, underlying);
}
@Override
protected ConfigRoot asRoot() {
return this;
}
@Override
public ConfigRoot resolve() {
return ((AbstractConfigObject) SubstitutionResolver.resolve(this, this))
.asRoot();
}
@Override
public RootConfigObject withFallback(ConfigValue value) {
return new RootConfigObject(super.withFallback(value));
}
}

View File

@ -1,67 +1,14 @@
package com.typesafe.config.impl;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import com.typesafe.config.ConfigException;
import com.typesafe.config.ConfigValue;
final class TransformedConfigObject extends AbstractConfigObject {
final private AbstractConfigObject underlying;
final class TransformedConfigObject extends DelegatingConfigObject {
TransformedConfigObject(ConfigTransformer transformer,
AbstractConfigObject underlying) {
super(underlying.origin(), transformer);
this.underlying = underlying;
super(transformer, underlying);
if (transformer == underlying.transformer)
throw new ConfigException.BugOrBroken(
"Created unnecessary TransformedConfigObject");
}
@Override
public boolean containsKey(Object key) {
return underlying.containsKey(key);
}
@Override
public Set<String> keySet() {
return underlying.keySet();
}
@Override
public Map<String, Object> unwrapped() {
return underlying.unwrapped();
}
@Override
protected AbstractConfigValue peek(String key) {
return underlying.peek(key);
}
@Override
public boolean containsValue(Object value) {
return underlying.containsValue(value);
}
@Override
public Set<java.util.Map.Entry<String, ConfigValue>> entrySet() {
return underlying.entrySet();
}
@Override
public boolean isEmpty() {
return underlying.isEmpty();
}
@Override
public int size() {
return underlying.size();
}
@Override
public Collection<ConfigValue> values() {
return underlying.values();
}
}