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

Posted

技术标签:

【中文标题】如何在 Typesafe Config 中获取未包装的密钥?【英文标题】:How do I get an unwrapped key in Typesafe Config? 【发布时间】:2014-03-11 08:58:45 【问题描述】:

测试用例:

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。有没有建议的解包方法,还是我每次都必须手动查找周围的引号并删除它们?

【问题讨论】:

entry.head.getKey === "\"quoted.key.1\"" @VincenzoMaggio,这是一个显示问题的测试用例。问题体现在代码中。如果我没有需要为 HOCON 引用的字符串,它会在 getKey 中不加引号地返回。我不想预测我的管理员将在那里输入的值。我只是想知道除了 entrySet 是否有其他方法可以让我打开它们。 【参考方案1】:

在此处的 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 会给你所有 leaf 值,而迭代 ConfigObject (config.root()) 会给你根的所有直接子节点,甚至如果这些直系孩子本身就是对象。

假设你有:

foo 
   bar 
       baz = 10
   

如果您将其作为Config 进行迭代,您将获得一个 条目,其中路径foo.bar.baz 作为键,值10。如果您将其作为ConfigObject 进行迭代,那么您将拥有一个条目,该条目将具有键foo,而值将是一个对象,该对象又将包含键bar。当将其迭代为 Config 时,您可以将 splitPath foo.bar.baz 进行迭代,您将得到一个包含三个字符串的数组,foobarbaz

要将Config 转换为ConfigObject 使用root() 方法,将ConfigObject 转换为Config 使用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"
  

【讨论】:

不,splitPath 是完全不同的东西。我不希望密钥成为路径,我想要未转义/未引用的键值。你能帮我一个忙,在我的原始配置示例或github.com/typesafehub/config/issues/144 上列出所有键值的配置示例上编写一个快速迭代吗? 配置是一棵树,所以没有“a”键值。对于给定的设置,您要么有一个路径,要么有 N 个键。如果 N 为 1(您的树是一层深),那么您可以获得一个密钥。价值。有两种方法;迭代 ConfigObject (这只是一个普通的 Java Map)或迭代 Config 和 splitPath 中的每个路径,这应该给你一个 1 元素数组。因此,要获取您 splitPath 的单个键值,然后执行 split[0]。我现在正在打电话,所以很难把代码写出来,但我认为很清楚该怎么做。 不清楚。采取directories dirone/path = "look I am quoting the value instead of the key", "dir.two's.path.has.a.dot.so.it.is.escaped.in.hocon/path" = someval 。当您执行conf.entrySet.map(e =&gt; println(e.getKey + ": " + e.getValue.unwrapped)) 之类的操作时,您会得到dirone/path: look I am quoting the value instead of the key"dir.two's.path.has.a.dot.so.it.is.escaped.in.hocon/path": someval。为什么我可以打开一个必须引用的值,而不是一个键?我希望这是有道理的。 我知道它们必须在 hocon 中被引用,我在问如何在 Typesafe 配置中接收未转义/未引用键的列表。 只需使用 ConfigObject 而不是 Config,它就像 JSON 一样,这也许是简短的答案。【参考方案2】:

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

【讨论】:

以上是关于如何在 Typesafe Config 中获取未包装的密钥?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用系统属性替换 Typesafe Config 文件中的占位符?

typesafe config 简单试用

如何使用 Enum 类型的字段执行 Typesafe JSON?

如何强制 Typesafe Activator 监听 0.0.0.0:8888

Typesafe Activator 里面的 sbt 在哪里?

如何从 typesafe redux-observable epic 中收听“@@router/LOCATION_CHANGE”动作