无法使用 circe 解码字段类型为 Map[String, String] 的对象

couldn't decode Object with field Type Map[String, String] using circe

我有一个案例 class,其中包含 Map[String, String]

类型的字段

完整的class定义是-

case class MyConfig(version: Int, pairs: Map[String, String]).

我要解码的 json 是 -

{  
   "version":1,
   "pairs":[  
      {  
         "key1":"value1",
         "key2":"value2"
      }
   ]
}

当我尝试将字符串解码为 MyConfig 对象 println(decode[MyConfig](jsonStr)) 时,出现以下错误 -

Left(DecodingFailure([K, V]Map[K, V], List(DownField(pairs)))).

完整代码为-

case class MyConfig(version: Int, pairs: Map[String, String])

  import io.circe._, io.circe.generic.auto._, io.circe.parser._, io.circe.syntax._

  val jsonStr = """    {
                  |       "version":1,
                  |       "pairs":[
                  |          {
                  |             "key1":"value1",
                  |             "key2":"value2"
                  |          }
                  |       ]
                  |    }  """.stripMargin

  println(jsonStr)

  println(decode[MyConfig](jsonStr))

我能够解码 Map json 对象,如演示的那样 here 但不能解码带有 map 字段的对象。

知道如何解决这个错误吗?

问题在于,一般派生的解码器会尝试将 "pairs" 值解析为 Map[String, String],这意味着它将寻找 JSON 对象,而您拥有的是一个 JSON 对象数组。

如果您坚持 MyConfig 定义和形状类似的输入,您最好编写自己的解码器,而不是使用 io.circe.generic.auto 推导解码器。使用 forProductN:

非常简单
case class MyConfig(version: Int, pairs: Map[String, String])

import io.circe.Decoder

implicit val decodeMyConfig: Decoder[MyConfig] =
  Decoder.forProduct2[MyConfig, Int, List[Map[String, String]]](
    "version",
    "pairs"
  ) {
    case (v, ps) => MyConfig(v, ps.flatten.toMap)
  }

然后,假设您已按上述方式定义 jsonStr

scala> import io.circe.parser.decode
import io.circe.parser.decode

scala> decode[MyConfig](jsonStr)
res0: Either[io.circe.Error,MyConfig] = Right(MyConfig(1,Map(key1 -> value1, key2 -> value2)))

或者您可以更改 MyConfig 以便 pairs 成员是 List[Map[String, String]],或者您可以更改 JSON 架构(或生成它的任何代码) 以省略 JSON 数组层。