2

I have a Map[String, String] object with I want to use as json. I have written an encoder for this type:

implicit val encodeMap: Encoder[Map[String, String]] = new Encoder[Map[String, String]] {
override def apply(values: Map[String, String]): Json = {
  values.toList
    .map(pair => Json.obj(
      (pair._1, pair._2.asJson)
    )).asJson
}
}

In addition to encoder, I need a decoder, but I don't have an idea how to write it. My best try so far:

implicit val decodeMap: Decoder[Map[String, String]] = new Decoder[Map[String, String]] {
final def apply(c: HCurser): Decoder.Result[Map[String, String]] = ???

}

Pretty basic, but I don't really know how to get into this problem.
Thanks!

Doe
  • 71
  • 1
  • 4

1 Answers1

1

Something like this should work but as Andy said above, you should be able to use automatic or semi-automatic derivation in this case.

import cats.syntax.either._

implicit val decodeMap: Decoder[Map[String, String]] = new Decoder[Map[String, String]] {
  override def apply(c: HCursor): Decoder.Result[Map[String, String]] = {
    c.keys.fold[Decoder.Result[Map[String, String]]](Right(Map.empty))(
      _.foldLeft(Map[String, String]().asRight[DecodingFailure])((res, k) => {
        res.flatMap((m: Map[String, String]) => {
          c.downField(k).as[String].fold(
            _.asLeft[Map[String, String]],
            v => (m + (k -> v)).asRight[DecodingFailure]
          )
        })
      })
    )
  }
}
Paul Medcraft
  • 1,386
  • 11
  • 23
  • 1
    My version without the cats dependency, barely tested, and written before I realized that a misconfiguration had me unable to use the built-in one: https://gist.github.com/colindean/8ac20a7508565848ae8dc5729ab4d5b1 – Colin Dean Aug 26 '20 at 14:14