3

尝试为包含选项映射的实体编写 json 格式。它引发以下错误

错误:(8, 68) 没有 play.api.libs.json.Format 实例可用于隐式范围内的 scala.Predef.Map[java.lang.String, scala.Option[scala.Double]](提示:如果在同一个文件中声明,请确保之前声明过)

代码片段:

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))
4

2 回答 2

4

您可以定义隐式:

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

基于答案

于 2017-11-08T14:58:48.000 回答
0

问题似乎是 play-json 宏无法使用嵌套类型变量:

Map[String, Option[Double]]

您可以使用中间类型包装选项

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

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

implicit val optionDoubleFormat = Json.format[OptionDouble]
implicit val personFormat = Json.format[Person]

val a: Map[String, OptionDouble] = Map("a" -> OptionDouble(None))
Json.toJson(Person(a))

另一种选择可能是手动编写格式化程序。

于 2017-11-08T14:40:03.040 回答