如何在typesafeconfig中将ConfigValue转换为List [ConfigObject]

时间:2016-12-10 18:35:35

标签: scala typesafe-config

我是Scala和typesafeconfig的新手。我有以下问题 - 我有这样的配置 -

a = [
      {
        b1 = [
          { 
            c1 = 3, 
            c2 = 4
          }, {
            c1 = 3, 
            c2 = 21
          }
        ]
      }, {
        b2 = [
          {
            c1 = 10, 
            c2 = 56
          }, 
          # ...many more elements
        ]
      }
      # .
      # .
      # .many more elements
    ]

我已经能够使用以下代码将上述内容放在Map [String,ConfigValue]中 -

val list : Iterable[ConfigObject] = config.getObjectList(PathTo 'a').asScala

val pairs = for {
  item: ConfigObject <- list
  entry : Entry[String, Config] <- item.entrySet().asScala
  key = entry.getKey
  value = entry.getValue.atKey(key)
 } yield (key, value)

pairs.toMap

在这个Map中我得到的键是b1,b2等 - 这很好但问题是我得到的值为ConfigValue(我没有找到一个好方法来捕获值List [ConfigObject]或更好的东西)。所以,例如,在运行时我可以看到我对应于键b1的值有两个条目 - {c1 = 3,c2 = 4}和{c1 = 3,c2 = 21}但是我无法遍历这两个条目一个,到达c1和c2。

所以,我对那些在TypeSafeConfig和Scala方面有一些经验的人的问题是 - 是否有更好的方法可以制作我的Map,以便我可以轻松地遍历b1,b2等中的值,或者是否有将我的当前值(即ConfigValue)转换为可迭代的更好的方法。

提前致谢!

2 个答案:

答案 0 :(得分:2)

就个人而言,我真的不喜欢Java typesafe配置对象上的接口。这看起来像是一个很好的库,用于向java对象添加更多scala友好的接口:

https://github.com/iheartradio/ficus

要解析您的值,所需的所有代码都是:

val config = ConfigFactory.parseString(
  """
    |a = [
    |      {
    |        b1 = [
    |          {
    |            c1 = 3,
    |            c2 = 4
    |          }, {
    |            c1 = 3,
    |            c2 = 21
    |          }
    |        ]
    |      }, {
    |        b2 = [
    |          {
    |            c1 = 10,
    |            c2 = 56
    |          },
    |          # ...many more elements
    |        ]
    |      }
    |      # .
    |      # .
    |      # .many more elements
    |    ]
  """.stripMargin)

import net.ceedubs.ficus.Ficus._

val myComplicatedStructure = config.as[List[Map[String, List[Map[String, Int]]]]]("a")
println(myComplicatedStructure)

// prints List(Map(b1 -> List(Map(c2 -> 4, c1 -> 3), Map(c2 -> 21, c1 -> 3))), Map(b2 -> List(Map(c2 -> 56, c1 -> 10))))

如果你不想添加另一个库,这将作为java中的一次性解析器工作:

  val myComplicatedStructureFromJava = config.getConfigList("a").asScala.toList.map{ relativeConfig =>

  relativeConfig.root().entrySet().asScala.map { entry =>

    val key = entry.getKey

    val configList2 = relativeConfig.getConfigList(key).asScala.toList

    key -> configList2.map{ relativeConfig2 =>

      relativeConfig2.root().entrySet().asScala.map{ entry2 =>

        val key2 = entry2.getKey

        key2 -> relativeConfig2.getInt(key2)

      }.toMap

    }
  }.toMap
}

println(myComplicatedStructureFromJava)

// prints List(Map(b1 -> List(Map(c2 -> 4, c1 -> 3), Map(c2 -> 21, c1 -> 3))), Map(b2 -> List(Map(c2 -> 56, c1 -> 10))))

// or, if you just want a List[Map[String, List[Config]]]

val myComplicatedStructureFromJava2: List[Map[String, List[Config]]] = config.getConfigList("a").asScala.toList.map{ relativeConfig =>

  relativeConfig.root().entrySet().asScala.map { entry =>

    val key = entry.getKey

    val configList2 = relativeConfig.getConfigList(key).asScala.toList

    key -> configList2
  }.toMap
}

println(myComplicatedStructureFromJava2)

// List(Map(b1 -> List(Config(SimpleConfigObject({"c1":3,"c2":4})), Config(SimpleConfigObject({"c1":3,"c2":21})))), Map(b2 -> List(Config(SimpleConfigObject({"c1":10,"c2":56})))))

答案 1 :(得分:1)

方法toMap位于Collection[(K, V)]类型的集合(2元组的集合)上,并返回Map[K, V]。重复的密钥丢失。您需要先按键对每个值进行分组,而不是调用pairs.toMap

pairs.groupBy(_._1)         // produces a Map[String, Array[(String, ConfigValue)]
  .mapValues(_.map(_._1))   // produces a Map[String, Array[ConfigValue] 

这使您能够根据需要迭代配置。

相关问题