add Config.entrySet() which returns the set of paths and non-null values

This commit is contained in:
Havoc Pennington 2011-12-02 18:44:11 -05:00
parent 38fb8d6834
commit f6fd02508e
3 changed files with 60 additions and 10 deletions

View File

@ -4,6 +4,8 @@
package com.typesafe.config;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* An immutable map from config paths to config values.
@ -54,10 +56,11 @@ import java.util.List;
* are performed for you though.
*
* <p>
* If you want to iterate over the contents of a {@code Config}, you have to get
* its {@code ConfigObject} with {@link #root()}, and then iterate over the
* {@code ConfigObject}.
*
* If you want to iterate over the contents of a {@code Config}, you can get its
* {@code ConfigObject} with {@link #root()}, and then iterate over the
* {@code ConfigObject} (which implements <code>java.util.Map</code>). Or, you
* can use {@link #entrySet()} which recurses the object tree for you and builds
* up a <code>Set</code> of all path-value pairs where the value is not null.
*
* <p>
* <em>Do not implement {@code Config}</em>; it should only be implemented by
@ -256,6 +259,17 @@ public interface Config extends ConfigMergeable {
*/
boolean isEmpty();
/**
* Returns the set of path-value pairs, excluding any null values, found by
* recursing {@link #root() the root object}. Note that this is very
* different from <code>root().entrySet()</code> which returns the set of
* immediate-child keys in the root object and includes null values.
*
* @return set of paths with non-null values, built up by recursing the
* entire tree of {@link ConfigObject}
*/
Set<Map.Entry<String, ConfigValue>> entrySet();
/**
*
* @param path

View File

@ -3,10 +3,13 @@
*/
package com.typesafe.config.impl;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import com.typesafe.config.Config;
@ -20,12 +23,10 @@ import com.typesafe.config.ConfigValue;
import com.typesafe.config.ConfigValueType;
/**
* One thing to keep in mind in the future: if any Collection-like APIs are
* added here, including iterators or size() or anything, then we'd have to
* grapple with whether ConfigNull values are "in" the Config (probably not) and
* we'd probably want to make the collection look flat - not like a tree. So the
* key-value pairs would be all the tree's leaf values, in a big flat list with
* their full paths.
* One thing to keep in mind in the future: as Collection-like APIs are added
* here, including iterators or size() or anything, they should be consistent
* with a one-level java.util.Map from paths to non-null values. Null values are
* not "in" the map.
*/
final class SimpleConfig implements Config, MergeableValue {
@ -73,6 +74,31 @@ final class SimpleConfig implements Config, MergeableValue {
return object.isEmpty();
}
private static void findPaths(Set<Map.Entry<String, ConfigValue>> entries, Path parent,
AbstractConfigObject obj) {
for (Map.Entry<String, ConfigValue> entry : obj.entrySet()) {
String elem = entry.getKey();
ConfigValue v = entry.getValue();
Path path = Path.newKey(elem);
if (parent != null)
path = path.prepend(parent);
if (v instanceof AbstractConfigObject) {
findPaths(entries, path, (AbstractConfigObject) v);
} else if (v instanceof ConfigNull) {
// nothing; nulls are conceptually not in a Config
} else {
entries.add(new AbstractMap.SimpleImmutableEntry<String, ConfigValue>(path.render(), v));
}
}
}
@Override
public Set<Map.Entry<String, ConfigValue>> entrySet() {
Set<Map.Entry<String, ConfigValue>> entries = new HashSet<Map.Entry<String, ConfigValue>>();
findPaths(entries, null, object);
return entries;
}
static private AbstractConfigValue find(AbstractConfigObject self,
String pathExpression, ConfigValueType expected, String originalPath) {
Path path = Path.newPath(pathExpression);

View File

@ -782,6 +782,16 @@ class ConfigTest extends TestUtils {
assertEquals(-1, o3.lineNumber)
}
@Test
def test01EntrySet() {
val conf = ConfigFactory.load("test01")
val javaEntries = conf.entrySet()
val entries = Map((javaEntries.asScala.toSeq map { e => (e.getKey(), e.getValue()) }): _*)
assertEquals(Some(intValue(42)), entries.get("ints.fortyTwo"))
assertEquals(None, entries.get("nulls.null"))
}
@Test
def test02SubstitutionsWithWeirdPaths() {
val conf = ConfigFactory.load("test02")