mirror of
https://github.com/lightbend/config.git
synced 2025-03-18 21:30:30 +08:00
allow duplicate keys in .conf with later key winning
This commit is contained in:
parent
df3b3792da
commit
a3128871ac
@ -290,13 +290,25 @@ final class Parser {
|
||||
|
||||
consolidateValueTokens();
|
||||
Token valueToken = nextTokenIgnoringNewline();
|
||||
AbstractConfigValue newValue = parseValue(valueToken);
|
||||
|
||||
// note how we handle duplicate keys: the last one just
|
||||
// wins.
|
||||
// FIXME in strict JSON, dups should be an error; while in
|
||||
// In strict JSON, dups should be an error; while in
|
||||
// our custom config language, they should be merged if the
|
||||
// value is an object.
|
||||
values.put(key, parseValue(valueToken));
|
||||
// value is an object (or substitution that could become
|
||||
// an object).
|
||||
AbstractConfigValue existing = values.get(key);
|
||||
|
||||
if (existing != null) {
|
||||
if (flavor == SyntaxFlavor.JSON) {
|
||||
throw parseError("JSON does not allow duplicate fields: '"
|
||||
+ key
|
||||
+ "' was already seen at "
|
||||
+ existing.origin().description());
|
||||
} else {
|
||||
newValue = newValue.withFallback(existing);
|
||||
}
|
||||
}
|
||||
values.put(key, newValue);
|
||||
|
||||
afterComma = false;
|
||||
} else if (t == Tokens.CLOSE_CURLY) {
|
||||
|
@ -116,4 +116,48 @@ class ConfParserTest extends TestUtils {
|
||||
parsePath("-")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
def duplicateKeyLastWins() {
|
||||
val obj = parseObject("""{ "a" : 10, "a" : 11 } """)
|
||||
|
||||
assertEquals(1, obj.size())
|
||||
assertEquals(11, obj.getInt("a"))
|
||||
}
|
||||
|
||||
@Test
|
||||
def duplicateKeyObjectsMerged() {
|
||||
val obj = parseObject("""{ "a" : { "x" : 1, "y" : 2 }, "a" : { "x" : 42, "z" : 100 } }""")
|
||||
|
||||
assertEquals(1, obj.size())
|
||||
assertEquals(3, obj.getObject("a").size())
|
||||
assertEquals(42, obj.getInt("a.x"))
|
||||
assertEquals(2, obj.getInt("a.y"))
|
||||
assertEquals(100, obj.getInt("a.z"))
|
||||
}
|
||||
|
||||
@Test
|
||||
def duplicateKeyObjectsMergedRecursively() {
|
||||
val obj = parseObject("""{ "a" : { "b" : { "x" : 1, "y" : 2 } }, "a" : { "b" : { "x" : 42, "z" : 100 } } }""")
|
||||
|
||||
assertEquals(1, obj.size())
|
||||
assertEquals(1, obj.getObject("a").size())
|
||||
assertEquals(3, obj.getObject("a.b").size())
|
||||
assertEquals(42, obj.getInt("a.b.x"))
|
||||
assertEquals(2, obj.getInt("a.b.y"))
|
||||
assertEquals(100, obj.getInt("a.b.z"))
|
||||
}
|
||||
|
||||
@Test
|
||||
def duplicateKeyObjectsMergedRecursivelyDeeper() {
|
||||
val obj = parseObject("""{ "a" : { "b" : { "c" : { "x" : 1, "y" : 2 } } }, "a" : { "b" : { "c" : { "x" : 42, "z" : 100 } } } }""")
|
||||
|
||||
assertEquals(1, obj.size())
|
||||
assertEquals(1, obj.getObject("a").size())
|
||||
assertEquals(1, obj.getObject("a.b").size())
|
||||
assertEquals(3, obj.getObject("a.b.c").size())
|
||||
assertEquals(42, obj.getInt("a.b.c.x"))
|
||||
assertEquals(2, obj.getInt("a.b.c.y"))
|
||||
assertEquals(100, obj.getInt("a.b.c.z"))
|
||||
}
|
||||
}
|
||||
|
@ -149,7 +149,6 @@ abstract trait TestUtils {
|
||||
"""{ "foo" : { "bar" : "baz" }, "baz" : "boo" }""",
|
||||
"""{ "foo" : { "bar" : "baz", "woo" : "w00t" }, "baz" : "boo" }""",
|
||||
"""{ "foo" : [10,11,12], "baz" : "boo" }""",
|
||||
ParseTest(true, """{ "foo" : "bar", "foo" : "bar2" }"""), // dup keys - lift just returns both, we use last one
|
||||
"""[{},{},{},{}]""",
|
||||
"""[[[[[[]]]]]]""",
|
||||
"""{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":42}}}}}}}}""",
|
||||
@ -160,6 +159,7 @@ abstract trait TestUtils {
|
||||
private val validConfInvalidJson = List[ParseTest](
|
||||
"""{ "foo" : bar }""", // no quotes on value
|
||||
"""{ "foo" : null bar 42 baz true 3.14 "hi" }""", // bunch of values to concat into a string
|
||||
ParseTest(true, """{ "foo" : "bar", "foo" : "bar2" }"""), // dup keys - lift just returns both
|
||||
"[ foo ]", // not a known token in JSON
|
||||
"[ t ]", // start of "true" but ends wrong in JSON
|
||||
"[ tx ]",
|
||||
|
Loading…
Reference in New Issue
Block a user