Encode and decode a Map[String, Any]

111 views Asked by At

I have to serialize my case class to Map[String, Any] instead of JSON, since the library I have to use only accepts the Map.

My case classes:

import io.circe._
import io.circe.generic.semiauto._

case class Book(title: String, price: Double, author: Author)

case class Author(firstName: String, lastName: String)

object Book {
  implicit val encoder: Encoder[Book] = deriveEncoder
  implicit val decoder: Decoder[Book] = deriveDecoder
}

object Author {
  implicit val encoder: Encoder[Author] = deriveEncoder
  implicit val decoder: Decoder[Author] = deriveDecoder
}

I have came up with the solution using circe:

val book = Book("Title", 23.99, Author("Foo", "Bar"))
val json = book.asJson
val map = json.as[Map[String, Json]].getOrElse(Map.empty)

However, theauthor value is represented as json in the result map, not as a Map.

How should it be fixed?

1

There are 1 answers

0
Dima On

Just write your own converter no need to mess with json at all.

object Mapper {
   implicit class ProductMapper(val p: Product) extends AnyVal {
      def asMap: Map[String, Any] = (p.productElementNames zip p.productIterator)
        .map { 
           case (k, v:Product) => k -> v.asMap
           case (k, v) => k -> v
        }.toMap
   }
}

import Mapper._ 
val bookAsMap = Book("foo", 1.0, Author("Bar", "Baz")).asMap 

Note: this simplistic implementation does not handle self-referencing/cyclic structures, you'd need to enhance it a little bit (add state variable to keep track of instances that were already seen) if that is a requirement.