2
votes

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!

1
Does import io.circe.generic.auto._ not just work here (allowing you to use .asJson) ? - Andy Hayden

1 Answers

1
votes

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]
          )
        })
      })
    )
  }
}