move a ConfigList interface up into the public API

This commit is contained in:
Havoc Pennington 2011-11-10 19:53:02 -05:00
parent 88b970982d
commit 3019aec77f
8 changed files with 59 additions and 26 deletions

View File

@ -0,0 +1,20 @@
package com.typesafe.config;
import java.util.List;
/**
* A list (aka array) value corresponding to ConfigValueType.LIST or JSON's
* "[1,2,3]" value. Implements java.util.List<ConfigValue> so you can use it
* like a regular Java list.
*
*/
public interface ConfigList extends List<ConfigValue>, ConfigValue {
/**
* Recursively unwraps the list, returning a list of plain Java values such
* as Integer or String or whatever is in the list.
*/
@Override
List<Object> unwrapped();
}

View File

@ -7,7 +7,7 @@ import java.util.Map;
* A ConfigObject is a read-only configuration object, which may have nested
* child objects. Implementations of ConfigObject should be immutable (at least
* from the perspective of anyone using this interface).
*
*
* The getters all have the same semantics; they throw ConfigException.Missing
* if the value is entirely unset, and ConfigException.WrongType if you ask for
* a type that the value can't be converted to. ConfigException.Null is a
@ -16,10 +16,10 @@ import java.util.Map;
* path "a.b.c" looks for key c in object b in object a in the root object. (The
* syntax for paths is the same as in ${} substitution expressions in config
* files, sometimes double quotes are needed around special characters.)
*
*
* ConfigObject implements the standard Java Map interface, but the mutator
* methods all throw UnsupportedOperationException.
*
*
* TODO add OrNull variants of all these getters? Or better to avoid convenience
* API for that?
*/
@ -74,8 +74,16 @@ public interface ConfigObject extends ConfigValue, Map<String, ConfigValue> {
*/
Long getNanoseconds(String path);
/* TODO should this return an iterator instead? */
List<? extends ConfigValue> getList(String path);
/**
* Gets a list value (with any element type) as a ConfigList, which
* implements java.util.List<ConfigValue>. Throws if the path is unset or
* null.
*
* @param path
* the path to the list value.
* @return the ConfigList at the path
*/
ConfigList getList(String path);
List<Boolean> getBooleanList(String path);

View File

@ -8,21 +8,22 @@ package com.typesafe.config;
public interface ConfigValue {
/**
* The origin of the value, for debugging and error messages.
*
*
* @return where the value came from
*/
ConfigOrigin origin();
/**
* The type of the value; matches the JSON type schema.
*
*
* @return value's type
*/
ConfigValueType valueType();
/**
* Returns the config value as a plain Java boxed value, should be a String,
* Number, etc. matching the valueType() of the ConfigValue.
* Number, etc. matching the valueType() of the ConfigValue. If the value is
* a ConfigObject or ConfigList, it is recursively unwrapped.
*/
Object unwrapped();
}

View File

@ -9,6 +9,7 @@ import java.util.concurrent.TimeUnit;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigException;
import com.typesafe.config.ConfigList;
import com.typesafe.config.ConfigObject;
import com.typesafe.config.ConfigOrigin;
import com.typesafe.config.ConfigValue;
@ -293,7 +294,7 @@ abstract class AbstractConfigObject extends AbstractConfigValue implements
}
@Override
public List<? extends ConfigValue> getList(String path) {
public ConfigList getList(String path) {
AbstractConfigValue v = find(path, ConfigValueType.LIST, path);
return (ConfigList) v;
}

View File

@ -322,7 +322,7 @@ final class Parser {
return new SimpleConfigObject(objectOrigin, null, values);
}
private ConfigList parseArray() {
private SimpleConfigList parseArray() {
// invoked just after the OPEN_SQUARE
ConfigOrigin arrayOrigin = lineOrigin();
List<AbstractConfigValue> values = new ArrayList<AbstractConfigValue>();
@ -333,7 +333,7 @@ final class Parser {
// special-case the first element
if (t == Tokens.CLOSE_SQUARE) {
return new ConfigList(arrayOrigin,
return new SimpleConfigList(arrayOrigin,
Collections.<AbstractConfigValue> emptyList());
} else if (Tokens.isValue(t)) {
values.add(parseValue(t));
@ -351,7 +351,7 @@ final class Parser {
// just after a value
t = nextTokenIgnoringNewline();
if (t == Tokens.CLOSE_SQUARE) {
return new ConfigList(arrayOrigin, values);
return new SimpleConfigList(arrayOrigin, values);
} else if (t == Tokens.COMMA) {
// OK
} else {

View File

@ -7,15 +7,16 @@ import java.util.List;
import java.util.ListIterator;
import com.typesafe.config.ConfigException;
import com.typesafe.config.ConfigList;
import com.typesafe.config.ConfigOrigin;
import com.typesafe.config.ConfigValue;
import com.typesafe.config.ConfigValueType;
final class ConfigList extends AbstractConfigValue implements List<ConfigValue> {
final class SimpleConfigList extends AbstractConfigValue implements ConfigList {
private List<AbstractConfigValue> value;
ConfigList(ConfigOrigin origin, List<AbstractConfigValue> value) {
SimpleConfigList(ConfigOrigin origin, List<AbstractConfigValue> value) {
super(origin);
this.value = value;
}
@ -35,7 +36,7 @@ final class ConfigList extends AbstractConfigValue implements List<ConfigValue>
}
@Override
ConfigList resolveSubstitutions(SubstitutionResolver resolver, int depth,
SimpleConfigList resolveSubstitutions(SubstitutionResolver resolver, int depth,
boolean withFallbacks) {
// lazy-create for optimization
List<AbstractConfigValue> changed = null;
@ -65,7 +66,7 @@ final class ConfigList extends AbstractConfigValue implements List<ConfigValue>
if (changed.size() != value.size())
throw new ConfigException.BugOrBroken(
"substituted list's size doesn't match");
return new ConfigList(origin(), changed);
return new SimpleConfigList(origin(), changed);
} else {
return this;
}
@ -73,15 +74,15 @@ final class ConfigList extends AbstractConfigValue implements List<ConfigValue>
@Override
protected boolean canEqual(Object other) {
return other instanceof ConfigList;
return other instanceof SimpleConfigList;
}
@Override
public boolean equals(Object other) {
// note that "origin" is deliberately NOT part of equality
if (other instanceof ConfigList) {
if (other instanceof SimpleConfigList) {
// optimization to avoid unwrapped() for two ConfigList
return canEqual(other) && value.equals(((ConfigList) other).value);
return canEqual(other) && value.equals(((SimpleConfigList) other).value);
} else {
return false;
}

View File

@ -6,6 +6,7 @@ import com.typesafe.config.ConfigValue
import java.util.Collections
import scala.collection.JavaConverters._
import com.typesafe.config.ConfigObject
import com.typesafe.config.ConfigList
class ConfigValueTest extends TestUtils {
@ -69,10 +70,10 @@ class ConfigValueTest extends TestUtils {
@Test
def configListEquality() {
val aScalaSeq = Seq(1, 2, 3) map { intValue(_): AbstractConfigValue }
val aList = new ConfigList(fakeOrigin(), aScalaSeq.asJava)
val sameAsAList = new ConfigList(fakeOrigin(), aScalaSeq.asJava)
val aList = new SimpleConfigList(fakeOrigin(), aScalaSeq.asJava)
val sameAsAList = new SimpleConfigList(fakeOrigin(), aScalaSeq.asJava)
val bScalaSeq = Seq(4, 5, 6) map { intValue(_): AbstractConfigValue }
val bList = new ConfigList(fakeOrigin(), bScalaSeq.asJava)
val bList = new SimpleConfigList(fakeOrigin(), bScalaSeq.asJava)
checkEqualObjects(aList, aList)
checkEqualObjects(aList, sameAsAList)
@ -101,7 +102,7 @@ class ConfigValueTest extends TestUtils {
nullValue().toString()
boolValue(true).toString()
(new SimpleConfigObject(fakeOrigin(), null, Collections.emptyMap[String, AbstractConfigValue]())).toString()
(new ConfigList(fakeOrigin(), Collections.emptyList[AbstractConfigValue]())).toString()
(new SimpleConfigList(fakeOrigin(), Collections.emptyList[AbstractConfigValue]())).toString()
subst("a").toString()
substInString("b").toString()
}
@ -153,8 +154,9 @@ class ConfigValueTest extends TestUtils {
@Test
def configListImplementsList() {
val l: ConfigList = new ConfigList(fakeOrigin(), List[AbstractConfigValue](stringValue("a"), stringValue("b"), stringValue("c")).asJava)
val scalaSeq = Seq(stringValue("a"), stringValue("b"), stringValue("c"))
val scalaSeq = Seq[AbstractConfigValue](stringValue("a"), stringValue("b"), stringValue("c"))
val l: ConfigList = new SimpleConfigList(fakeOrigin(),
scalaSeq.asJava)
assertEquals(scalaSeq(0), l.get(0))
assertEquals(scalaSeq(1), l.get(1))

View File

@ -51,7 +51,7 @@ class JsonTest extends TestUtils {
fields.foreach({ field => m.put(field.name, fromLift(field.value)) })
new SimpleConfigObject(fakeOrigin(), null, m)
case lift.JArray(values) =>
new ConfigList(fakeOrigin(), values.map(fromLift(_)).asJava)
new SimpleConfigList(fakeOrigin(), values.map(fromLift(_)).asJava)
case lift.JField(name, value) =>
throw new IllegalStateException("either JField was a toplevel from lift-json or this function is buggy")
case lift.JInt(i) =>