не удалось декодировать объект с помощью поля Type Map [String, String] с использованием circe - PullRequest
0 голосов
/ 04 января 2019

У меня есть класс case, который содержит поле типа Map[String, String]

Полное определение класса -

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, как показано здесь , но не объект с полем карты.

Есть идеи, как решить эту ошибку?

1 Ответ

0 голосов
/ 04 января 2019

Проблема заключается в том, что декодер общего назначения попытается проанализировать значение "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.

...