Skip to content

Instantly share code, notes, and snippets.

@colindean
Created August 25, 2020 20:10
Show Gist options
  • Save colindean/8ac20a7508565848ae8dc5729ab4d5b1 to your computer and use it in GitHub Desktop.
Save colindean/8ac20a7508565848ae8dc5729ab4d5b1 to your computer and use it in GitHub Desktop.
A Map[String, String] decoder for Circe
// warning: barely tested
import io.circe.Decoder.Result
import io.circe._
import io.circe.generic.extras._
object CirceMapDecoder {
type KeyVal = Map[String, String]
// using the expansion may be necessary for Circe to detect it correctly
implicit val decodeMap: Decoder[Map[String, String]] = new Decoder[Map[String, String]] {
override def apply(c: HCursor): Decoder.Result[KeyVal] = {
def extractValueForKeyInto(res: Decoder.Result[KeyVal], key: String): Decoder.Result[KeyVal] = {
res.right.flatMap((map: KeyVal) => {
c.downField(key).as[String].fold(
Left(_),
value => Right(map + (key -> value))
)
})
}
def emptyMapResult: Decoder.Result[KeyVal] = Right(Map[String, String]().empty)
def withKeys(keys: Iterable[String]): Decoder.Result[KeyVal] = keys.foldLeft(emptyMapResult)(extractValueForKeyInto)
c.keys.fold[Decoder.Result[KeyVal]](ifEmpty = emptyMapResult)(withKeys)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment