尝试为此案例类编写json格式化程序
case class OptionRange[+T](start: Option[T], end: Option[T])
这是我到目前为止所拥有的
implicit def fmt[T <: OptionRange[_]](implicit fmt: Format[Option[T]]): Format[OptionRange[T]] = new Format[OptionRange[T]] {
def reads(json: JsValue): JsSuccess[OptionRange[T]] = JsSuccess(new OptionRange[T] (
(json \ "start").as[Option[T]],
(json \ "end").as[Option[T]]
))
def writes(i: OptionRange[T]) = JsObject(Seq(
"start" -> Json.toJson(i.start),
"end" -> Json.toJson(i.end)
))
}
这段代码编译但是当我尝试格式化OptionRange[Int]
时,我得到一个错误,即没有可用的隐式格式。
如何编写隐式范围内可用的格式?
答案 0 :(得分:2)
您正在进行一些循环类型定义。
在我看来,在这种情况下,您希望将T
评估为Int
。但是,在函数定义中,您已约束[T <: OptionRange[_]]
。因此,Scala认为T
必须是某个OptionRange
。
当您转到函数(implicit fmt: Format[Option[T]])
的隐式参数时,这会变得更加复杂。如果T
为OptionRange[_]
,那么您告诉编译器需要Format[Option[OptionRange[_]]]
而不是Format[Option[_]]
。您的功能不能成为Format
的来源,因为无法对其进行评估以提供隐含的要求。
解决方案是停止约束T
。
implicit def fmt[T](implicit fmt: Format[Option[T]]) ...
然后,当您尝试将OptionRange
格式化为json:
scala> import play.api.libs.json._
import play.api.libs.json._
scala> case class OptionRange[+T](start: Option[T], end: Option[T])
defined class OptionRange
scala> implicit def fmt[T](implicit fmt: Format[Option[T]]): Format[OptionRange[T]] = new Format[OptionRange[T]] {
| def reads(json: JsValue): JsSuccess[OptionRange[T]] = JsSuccess(new OptionRange[T] (
| (json \ "start").as[Option[T]],
| (json \ "end").as[Option[T]]
| ))
| def writes(i: OptionRange[T]) = JsObject(Seq(
| "start" -> Json.toJson(i.start),
| "end" -> Json.toJson(i.end)
| ))
| }
fmt: [T](implicit fmt: play.api.libs.json.Format[Option[T]])play.api.libs.json.Format[OptionRange[T]]
scala> Json.toJson(OptionRange(Some(1), Some(2)))
res0: play.api.libs.json.JsValue = {"start":1,"end":2}
答案 1 :(得分:1)
以下是使用播放框架2.3.9
,Scala 2.11.8
的一种方法:
import play.api.libs.json._ // JSON library
import play.api.libs.json.Reads._ // Custom validation helpers
import play.api.libs.functional.syntax._ // Combinator syntax
case class OptionRange[+T](start: Option[T], end: Option[T])
object Hello extends App {
implicit def formatOptionRange[T](implicit formatT: Format[T]): Format[OptionRange[T]] =
(
(JsPath \ "start").formatNullable[T] and
(JsPath \ "end").formatNullable[T]
)(OptionRange.apply, unlift(OptionRange.unapply))
println(Json.toJson(OptionRange(Some(1), Some(2))))
}
//Prints:
//{"start":1,"end":2}
这是format上的文档。