如何在Typesafe配置中获取未包装的密钥?

Cha*_*etz 8 scala typesafe typesafe-config

测试用例:

import org.specs2.mutable._
class HelloWorldSpec extends Specification {
  "Typesafe Config" should "allow me to see my escaped key" in {
    val entries = ConfigFactory.parseString("""
      "quoted.key.1" = 5
      "quoted.key.2" = 6""").entrySet
    entries.head.getKey === "quoted.key.1"
  }
}
Run Code Online (Sandbox Code Playgroud)

此测试失败,因为密钥实际上"quoted.key.1"不是quoted.key.1.是否有建议的方法来解开这个或我是否必须手动查找周围的引号并每次删除它们?

Hav*_*c P 8

请阅读API文档中的"路径,键和Config与ConfigObject":http://typesafehub.github.io/config/latest/api/com/typesafe/config/Config.html, 并在README中:https://github.com/typesafehub/config#understanding-config-and-configobject

(欢迎提出改进这些文档的建议.)

条目集(和Config)中的键是路径表达式.这些是需要解析的字符串.ConfigUtil中有一个解析方法,请参阅http://typesafehub.github.io/config/latest/api/com/typesafe/config/ConfigUtil.html#splitPath%28java.lang.String%29

仅仅删除引号是不行的,解析比这更复杂.幸运的是,您可以使用该ConfigUtil.splitPath方法.

因此,在根级别迭代键的两种方法类似于,首先使用Config:

Config config = ... ;
for (Map.Entry<String, ConfigValue> entry: config.entrySet()) {
  String[] keys = ConfigUtil.splitPath(entry.getKey());
  System.out.println("Root key = " + keys[0]);
}
Run Code Online (Sandbox Code Playgroud)

然后使用ConfigObject:

Config config = ... ;
for (Map.Entry<String, ConfigValue> entry: config.root().entrySet()) {
  System.out.println("Root key = " + entry.getKey());
}
Run Code Online (Sandbox Code Playgroud)

我没有尝试编译上面的例子,所以请原谅任何愚蠢的语法错误.

如果您的配置只包含一个级别(没有嵌套对象),则上述两种迭代方式是相同的; 但是如果你有嵌套值,它们就不一样了,因为iterating Config会给你所有的叶子值,而iterating ConfigObject(config.root())会给你所有的直接子节点,即使这些直接子节点本身就是对象.

说你有:

foo {
   bar {
       baz = 10
   }
}
Run Code Online (Sandbox Code Playgroud)

如果你迭代它,Config你会得到一个条目,它将路径foo.bar.baz作为键和值10.如果你把它作为a迭代,ConfigObject那么你将有一个具有键的条目,foo而值将是一个对象,而该对象又包含密钥bar.当迭代这是一个Config你可以splitPathfoo.bar.baz,你会得到三个字符串,数组foo,barbaz.

要转换ConfigConfigObject使用root()方法并转换ConfigObjectConfig使用该toConfig()方法.所以config.root().toConfig() == config.

此外,上面的配置文件可以等效地写为:

foo.bar.baz = 10
Run Code Online (Sandbox Code Playgroud)

但如果写成:

"foo.bar.baz" = 10
Run Code Online (Sandbox Code Playgroud)

因为在第一种情况下,您具有嵌套对象,而在第二种情况下,您有一个在键名称中具有句点的对象.这是由于报价.

如果你"foo.bar.baz"用引号写,那么在迭代Config你回来的路径时会引用并splitPath()返回一个元素的数组foo.bar.baz.迭代时,ConfigObject您将拥有一个包含带foo.bar.baz键和10值的条目的单个对象..必须引用包含或其他特殊字符的键,以便将它们解释为单个键而不是路径.

为了使您的测试用例通过,您可以使用splitPath执行此操作:

import org.specs2.mutable._
class HelloWorldSpec extends Specification {
  "Typesafe Config" should "allow me to see my escaped key" in {
    val entries = ConfigFactory.parseString("""
      "quoted.key.1" = 5
      "quoted.key.2" = 6""").entrySet
    // the ordering of entrySet is not guaranteed so this may
    // still fail because it gets quoted.key.2 instead
    ConfigUtil.splitPath(entries.head.getKey).head === "quoted.key.1"
  }
}
Run Code Online (Sandbox Code Playgroud)

你也可以这样做,使用ConfigObject:

import org.specs2.mutable._
class HelloWorldSpec extends Specification {
  "Typesafe Config" should "allow me to see my escaped key" in {
    val entries = ConfigFactory.parseString("""
      "quoted.key.1" = 5
      "quoted.key.2" = 6""").root.entrySet // note ".root." here
    // the ordering of entrySet is not guaranteed so this may
    // still fail because it gets quoted.key.2 instead
    // no need to splitPath because ConfigObject has keys not paths
    entries.head.getKey === "quoted.key.1"
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 只需使用 ConfigObject 而不是 Config ,它就会像 JSON 一样,这也许是简短的答案。 (2认同)