make ConfigList implement java.util.List

This commit is contained in:
Havoc Pennington 2011-11-10 19:36:42 -05:00
parent be63b620f6
commit 88b970982d
7 changed files with 286 additions and 9 deletions

View File

@ -295,7 +295,7 @@ abstract class AbstractConfigObject extends AbstractConfigValue implements
@Override
public List<? extends ConfigValue> getList(String path) {
AbstractConfigValue v = find(path, ConfigValueType.LIST, path);
return ((ConfigList) v).asJavaList();
return (ConfigList) v;
}
@Override

View File

@ -1,14 +1,17 @@
package com.typesafe.config.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import com.typesafe.config.ConfigException;
import com.typesafe.config.ConfigOrigin;
import com.typesafe.config.ConfigValue;
import com.typesafe.config.ConfigValueType;
final class ConfigList extends AbstractConfigValue {
final class ConfigList extends AbstractConfigValue implements List<ConfigValue> {
private List<AbstractConfigValue> value;
@ -17,10 +20,6 @@ final class ConfigList extends AbstractConfigValue {
this.value = value;
}
List<? extends ConfigValue> asJavaList() {
return value;
}
@Override
public ConfigValueType valueType() {
return ConfigValueType.LIST;
@ -108,4 +107,196 @@ final class ConfigList extends AbstractConfigValue {
sb.append(")");
return sb.toString();
}
@Override
public boolean contains(Object o) {
return value.contains(o);
}
@Override
public boolean containsAll(Collection<?> c) {
return value.containsAll(c);
}
@Override
public ConfigValue get(int index) {
return value.get(index);
}
@Override
public int indexOf(Object o) {
return value.indexOf(o);
}
@Override
public boolean isEmpty() {
return value.isEmpty();
}
@Override
public Iterator<ConfigValue> iterator() {
final Iterator<AbstractConfigValue> i = value.iterator();
return new Iterator<ConfigValue>() {
@Override
public boolean hasNext() {
return i.hasNext();
}
@Override
public ConfigValue next() {
return i.next();
}
@Override
public void remove() {
throw weAreImmutable("iterator().remove");
}
};
}
@Override
public int lastIndexOf(Object o) {
return value.lastIndexOf(o);
}
private static ListIterator<ConfigValue> wrapListIterator(
final ListIterator<AbstractConfigValue> i) {
return new ListIterator<ConfigValue>() {
@Override
public boolean hasNext() {
return i.hasNext();
}
@Override
public ConfigValue next() {
return i.next();
}
@Override
public void remove() {
throw weAreImmutable("listIterator().remove");
}
@Override
public void add(ConfigValue arg0) {
throw weAreImmutable("listIterator().add");
}
@Override
public boolean hasPrevious() {
return i.hasPrevious();
}
@Override
public int nextIndex() {
return i.nextIndex();
}
@Override
public ConfigValue previous() {
return i.previous();
}
@Override
public int previousIndex() {
return i.previousIndex();
}
@Override
public void set(ConfigValue arg0) {
throw weAreImmutable("listIterator().set");
}
};
}
@Override
public ListIterator<ConfigValue> listIterator() {
return wrapListIterator(value.listIterator());
}
@Override
public ListIterator<ConfigValue> listIterator(int index) {
return wrapListIterator(value.listIterator(index));
}
@Override
public int size() {
return value.size();
}
@Override
public List<ConfigValue> subList(int fromIndex, int toIndex) {
List<ConfigValue> list = new ArrayList<ConfigValue>();
// yay bloat caused by lack of type variance
for (AbstractConfigValue v : value.subList(fromIndex, toIndex)) {
list.add(v);
}
return list;
}
@Override
public Object[] toArray() {
return value.toArray();
}
@Override
public <T> T[] toArray(T[] a) {
return value.toArray(a);
}
private static UnsupportedOperationException weAreImmutable(String method) {
return new UnsupportedOperationException(
"ConfigList is immutable, you can't call List.'" + method + "'");
}
@Override
public boolean add(ConfigValue e) {
throw weAreImmutable("add");
}
@Override
public void add(int index, ConfigValue element) {
throw weAreImmutable("add");
}
@Override
public boolean addAll(Collection<? extends ConfigValue> c) {
throw weAreImmutable("addAll");
}
@Override
public boolean addAll(int index, Collection<? extends ConfigValue> c) {
throw weAreImmutable("addAll");
}
@Override
public void clear() {
throw weAreImmutable("clear");
}
@Override
public boolean remove(Object o) {
throw weAreImmutable("remove");
}
@Override
public ConfigValue remove(int index) {
throw weAreImmutable("remove");
}
@Override
public boolean removeAll(Collection<?> c) {
throw weAreImmutable("removeAll");
}
@Override
public boolean retainAll(Collection<?> c) {
throw weAreImmutable("retainAll");
}
@Override
public ConfigValue set(int index, ConfigValue element) {
throw weAreImmutable("set");
}
}

View File

@ -34,7 +34,8 @@
"ofNull" : [null, null, null],
"ofBoolean" : [true, false],
"ofArray" : [${arrays.ofString}, ${arrays.ofString}, ${arrays.ofString}],
"ofObject" : [${ints}, ${booleans}, ${strings}]
"ofObject" : [${ints}, ${booleans}, ${strings}],
"firstElementNotASubst" : [ "a", ${strings.b} ]
},
"booleans" : {

View File

@ -56,7 +56,7 @@ class ConfParserTest extends TestUtils {
val tree = parseWithoutResolving("[${" + s + "}]")
val result = tree match {
case list: ConfigList =>
list.asJavaList().get(0) match {
list.get(0) match {
case subst: ConfigSubstitution =>
subst.pieces().get(0) match {
case p: Path => p

View File

@ -194,6 +194,8 @@ class ConfigTest extends TestUtils {
assertEquals(Seq(Seq("a", "b", "c"), Seq("a", "b", "c"), Seq("a", "b", "c")), listOfLists)
assertEquals(3, conf.getObjectList("arrays.ofObject").asScala.length)
assertEquals(Seq("a", "b"), conf.getStringList("arrays.firstElementNotASubst").asScala)
// plain getList should work
assertEquals(Seq(intValue(1), intValue(2), intValue(3)), conf.getList("arrays.ofInt").asScala)
assertEquals(Seq(stringValue("a"), stringValue("b"), stringValue("c")), conf.getList("arrays.ofString").asScala)

View File

@ -66,6 +66,19 @@ class ConfigValueTest extends TestUtils {
checkNotEqualObjects(a, b)
}
@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 bScalaSeq = Seq(4, 5, 6) map { intValue(_): AbstractConfigValue }
val bList = new ConfigList(fakeOrigin(), bScalaSeq.asJava)
checkEqualObjects(aList, aList)
checkEqualObjects(aList, sameAsAList)
checkNotEqualObjects(aList, bList)
}
@Test
def configSubstitutionEquality() {
val a = subst("foo")
@ -137,4 +150,74 @@ class ConfigValueTest extends TestUtils {
unsupported { m.putAll(Collections.emptyMap[String, AbstractConfigValue]()) }
unsupported { m.remove("a") }
}
@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"))
assertEquals(scalaSeq(0), l.get(0))
assertEquals(scalaSeq(1), l.get(1))
assertEquals(scalaSeq(2), l.get(2))
assertTrue(l.contains(stringValue("a")))
assertTrue(l.containsAll(List[AbstractConfigValue](stringValue("b")).asJava))
assertFalse(l.containsAll(List[AbstractConfigValue](stringValue("d")).asJava))
assertEquals(1, l.indexOf(scalaSeq(1)))
assertFalse(l.isEmpty());
assertEquals(scalaSeq, l.iterator().asScala.toSeq)
unsupported { l.iterator().remove() }
assertEquals(1, l.lastIndexOf(scalaSeq(1)))
val li = l.listIterator()
var i = 0
while (li.hasNext()) {
assertEquals(i > 0, li.hasPrevious())
assertEquals(i, li.nextIndex())
assertEquals(i - 1, li.previousIndex())
unsupported { li.remove() }
unsupported { li.add(intValue(3)) }
unsupported { li.set(stringValue("foo")) }
val v = li.next()
assertEquals(l.get(i), v)
if (li.hasPrevious()) {
// go backward
assertEquals(scalaSeq(i), li.previous())
// go back forward
li.next()
}
i += 1
}
l.listIterator(1) // doesn't throw!
assertEquals(3, l.size())
assertEquals(scalaSeq.tail, l.subList(1, l.size()).asScala)
assertEquals(scalaSeq, l.toArray.toList)
assertEquals(scalaSeq, l.toArray(new Array[ConfigValue](l.size())).toList)
unsupported { l.add(intValue(3)) }
unsupported { l.add(1, intValue(4)) }
unsupported { l.addAll(List[ConfigValue]().asJava) }
unsupported { l.addAll(1, List[ConfigValue]().asJava) }
unsupported { l.clear() }
unsupported { l.remove(intValue(2)) }
unsupported { l.remove(1) }
unsupported { l.removeAll(List[ConfigValue](intValue(1)).asJava) }
unsupported { l.retainAll(List[ConfigValue](intValue(1)).asJava) }
unsupported { l.set(0, intValue(42)) }
}
}

View File

@ -26,7 +26,7 @@ class JsonTest extends TestUtils {
case v: ConfigObject =>
lift.JObject(v.keySet().asScala.map({ k => lift.JField(k, toLift(v.get(k))) }).toList)
case v: ConfigList =>
lift.JArray(v.asJavaList().asScala.toList.map({ elem => toLift(elem) }))
lift.JArray(v.asScala.toList.map({ elem => toLift(elem) }))
case v: ConfigBoolean =>
lift.JBool(v.unwrapped())
case v: ConfigInt =>