8

测试用例:

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"
  }
}

这个测试失败了,因为关键实际上是"quoted.key.1",不是quoted.key.1。有没有建议的方法来解开这个,还是我每次都必须手动查找周围的引号并删除它们?

4

2 回答 2

10

在此处的 API 文档中阅读“路径、键和 Config 与 ConfigObject”:http: //typesafehub.github.io/config/latest/api/com/typesafe/config/Config.html 和此处的自述文件:https://github.com/typesafehub/config#understanding-config-and-configobject

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

条目集中(和配置)中的键是路径表达式。这些是需要解析的字符串。ConfigUtil中有parse方法,见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]);
}

然后使用 ConfigObject:

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

我没有尝试编译上述示例,因此请原谅任何愚蠢的语法错误。

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

假设你有:

foo {
   bar {
       baz = 10
   }
}

如果您将其作为 a 进行迭代,Config您将获得一个条目,其中路径foo.bar.baz为 key 和 value 10。如果您将其作为 a 进行迭代,ConfigObject那么您将拥有一个条目,该条目将具有 key foo,而 value 将是一个对象,该对象又将包含 key bar。当以 a 进行迭代时,Config你会得到一个包含三个字符串 、 、和的数组。splitPathfoo.bar.bazfoobarbaz

将 a 转换Config为 aConfigObject使用该root()方法并转换ConfigObjectConfig使用该toConfig()方法。所以config.root().toConfig() == config

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

foo.bar.baz = 10

但如果写成如下:

"foo.bar.baz" = 10

因为在第一种情况下,您有嵌套对象,而在第二种情况下,您有一个对象,键名中有句点。这是由于引号。

如果您"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"
  }
}

你也可以这样做,使用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"
  }
}
于 2014-02-13T19:48:49.910 回答
0

在 java 中,首先将整个ConfigObject展开为 hashmap,然后您可以使用quoted.key.1(不带引号)作为获取正确值的键。

于 2018-11-21T03:56:57.523 回答