mirror of
https://github.com/lightbend/config.git
synced 2025-02-23 09:41:01 +08:00
Try to convert objects with numeric keys to lists
This is mostly intended to provide a way to specify lists on the command line via Java properties, like -Dfoo.0 -Dfoo.1 Fixes #69
This commit is contained in:
parent
145a9be612
commit
338150f281
@ -3,6 +3,13 @@
|
|||||||
*/
|
*/
|
||||||
package com.typesafe.config.impl;
|
package com.typesafe.config.impl;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import com.typesafe.config.ConfigValueType;
|
import com.typesafe.config.ConfigValueType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -74,6 +81,49 @@ final class DefaultTransformer {
|
|||||||
// no-op STRING to STRING
|
// no-op STRING to STRING
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} else if (requested == ConfigValueType.LIST && value.valueType() == ConfigValueType.OBJECT) {
|
||||||
|
// attempt to convert an array-like (numeric indices) object to a
|
||||||
|
// list. This would be used with .properties syntax for example:
|
||||||
|
// -Dfoo.0=bar -Dfoo.1=baz
|
||||||
|
// To ensure we still throw type errors for objects treated
|
||||||
|
// as lists in most cases, we'll refuse to convert if the object
|
||||||
|
// does not contain any numeric keys. This means we don't allow
|
||||||
|
// empty objects here though :-/
|
||||||
|
AbstractConfigObject o = (AbstractConfigObject) value;
|
||||||
|
Map<Integer, AbstractConfigValue> values = new HashMap<Integer, AbstractConfigValue>();
|
||||||
|
for (String key : o.keySet()) {
|
||||||
|
int i;
|
||||||
|
try {
|
||||||
|
i = Integer.parseInt(key, 10);
|
||||||
|
if (i < 0)
|
||||||
|
continue;
|
||||||
|
values.put(i, o.get(key));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!values.isEmpty()) {
|
||||||
|
ArrayList<Map.Entry<Integer, AbstractConfigValue>> entryList = new ArrayList<Map.Entry<Integer, AbstractConfigValue>>(
|
||||||
|
values.entrySet());
|
||||||
|
// sort by numeric index
|
||||||
|
Collections.sort(entryList,
|
||||||
|
new Comparator<Map.Entry<Integer, AbstractConfigValue>>() {
|
||||||
|
@Override
|
||||||
|
public int compare(Map.Entry<Integer, AbstractConfigValue> a,
|
||||||
|
Map.Entry<Integer, AbstractConfigValue> b) {
|
||||||
|
// Integer.compare was added in 1.7 so not using
|
||||||
|
// it here yet
|
||||||
|
return Integer.valueOf(a.getKey()).compareTo(b.getKey());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// drop the indices (we allow gaps in the indices, for better or
|
||||||
|
// worse)
|
||||||
|
ArrayList<AbstractConfigValue> list = new ArrayList<AbstractConfigValue>();
|
||||||
|
for (Map.Entry<Integer, AbstractConfigValue> entry : entryList) {
|
||||||
|
list.add(entry.getValue());
|
||||||
|
}
|
||||||
|
return new SimpleConfigList(value.origin(), list);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
|
@ -9,6 +9,7 @@ import java.util.Properties
|
|||||||
import com.typesafe.config.Config
|
import com.typesafe.config.Config
|
||||||
import com.typesafe.config.ConfigParseOptions
|
import com.typesafe.config.ConfigParseOptions
|
||||||
import com.typesafe.config.ConfigFactory
|
import com.typesafe.config.ConfigFactory
|
||||||
|
import com.typesafe.config.ConfigException
|
||||||
|
|
||||||
class PropertiesTest extends TestUtils {
|
class PropertiesTest extends TestUtils {
|
||||||
@Test
|
@Test
|
||||||
@ -92,4 +93,63 @@ class PropertiesTest extends TestUtils {
|
|||||||
assertEquals("foo", conf.getString("a.b"))
|
assertEquals("foo", conf.getString("a.b"))
|
||||||
assertEquals("foo", conf.getString("x.y.z"))
|
assertEquals("foo", conf.getString("x.y.z"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
def makeListWithNumericKeys() {
|
||||||
|
import scala.collection.JavaConverters._
|
||||||
|
|
||||||
|
val props = new Properties()
|
||||||
|
props.setProperty("a.0", "0")
|
||||||
|
props.setProperty("a.1", "1")
|
||||||
|
props.setProperty("a.2", "2")
|
||||||
|
props.setProperty("a.3", "3")
|
||||||
|
props.setProperty("a.4", "4")
|
||||||
|
|
||||||
|
val conf = ConfigFactory.parseProperties(props, ConfigParseOptions.defaults())
|
||||||
|
assertEquals(Seq(0, 1, 2, 3, 4), conf.getIntList("a").asScala.toSeq)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
def makeListWithNumericKeysWithGaps() {
|
||||||
|
import scala.collection.JavaConverters._
|
||||||
|
|
||||||
|
val props = new Properties()
|
||||||
|
props.setProperty("a.1", "0")
|
||||||
|
props.setProperty("a.2", "1")
|
||||||
|
props.setProperty("a.4", "2")
|
||||||
|
|
||||||
|
val conf = ConfigFactory.parseProperties(props, ConfigParseOptions.defaults())
|
||||||
|
assertEquals(Seq(0, 1, 2), conf.getIntList("a").asScala.toSeq)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
def makeListWithNumericKeysWithNoise() {
|
||||||
|
import scala.collection.JavaConverters._
|
||||||
|
|
||||||
|
val props = new Properties()
|
||||||
|
props.setProperty("a.-1", "-1")
|
||||||
|
props.setProperty("a.foo", "-2")
|
||||||
|
props.setProperty("a.0", "0")
|
||||||
|
props.setProperty("a.1", "1")
|
||||||
|
props.setProperty("a.2", "2")
|
||||||
|
props.setProperty("a.3", "3")
|
||||||
|
props.setProperty("a.4", "4")
|
||||||
|
|
||||||
|
val conf = ConfigFactory.parseProperties(props, ConfigParseOptions.defaults())
|
||||||
|
assertEquals(Seq(0, 1, 2, 3, 4), conf.getIntList("a").asScala.toSeq)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
def noNumericKeysAsListFails() {
|
||||||
|
import scala.collection.JavaConverters._
|
||||||
|
|
||||||
|
val props = new Properties()
|
||||||
|
props.setProperty("a.bar", "0")
|
||||||
|
|
||||||
|
val conf = ConfigFactory.parseProperties(props, ConfigParseOptions.defaults())
|
||||||
|
val e = intercept[ConfigException.WrongType] {
|
||||||
|
conf.getList("a")
|
||||||
|
}
|
||||||
|
assertTrue("expected exception thrown", e.getMessage.contains("LIST"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user