使用泛型类

时间:2016-12-01 20:29:21

标签: json scala playframework playframework-2.4

尝试为此案例类编写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]时,我得到一个错误,即没有可用的隐式格式。

如何编写隐式范围内可用的格式?

2 个答案:

答案 0 :(得分:2)

您正在进行一些循环类型定义。

在我看来,在这种情况下,您希望将T评估为Int。但是,在函数定义中,您已约束[T <: OptionRange[_]]。因此,Scala认为T必须是某个OptionRange

当您转到函数(implicit fmt: Format[Option[T]])的隐式参数时,这会变得更加复杂。如果TOptionRange[_],那么您告诉编译器需要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上的文档。