Search code examples
jsonscalaplayframeworkplay-json

No instance of play.api.libs.json.Format is available for scala.Predef.Map[java.lang.String, scala.Option[scala.Double]]


Trying to write a json format for an entity which contains a Map of Option. It throws following error

Error:(8, 68) No instance of play.api.libs.json.Format is available for scala.Predef.Map[java.lang.String, scala.Option[scala.Double]] in the implicit scope (Hint: if declared in the same file, make sure it's declared before)

Code snippet:

import play.api.libs.json.{Json, OFormat}

val a: Map[String, Option[Double]] = Map("a" -> None)

case class Person(x: Map[String, Option[Double]])

object Person {
  implicit val personFormat: OFormat[Person] = Json.format[Person]
}

Json.toJson(Person(a))

Solution

  • You can define implicits:

      import scala.collection.Map
    
      object Person {
        implicit object MapReads extends Reads[Map[String, Option[Double]]] {
          def reads(jsValue: JsValue): JsResult[Map[String, Option[Double]]] = jsValue match {
            case JsObject(map) => JsSuccess(
              map.mapValues {
                case JsNumber(d) => Some(d.toDouble)
                case _ => None
              }
            )
            case _ => JsError()
          }
        }
    
        implicit object MapWrites extends Writes[Map[String, Option[Double]]] {
          def writes(map: Map[String, Option[Double]]): JsValue =
            JsObject(map.mapValues(optd => JsNumber(optd.getOrElse[Double](0.0))))
        }
    
        implicit val personFormat: OFormat[Person] = Json.format[Person]
      }
    
      println(Json.toJson(Person(a)))//{"x":{"a":0}}
    

    Based on answer.