如何使用spray-json将“asJson”方法作为案例类的一部分?

时间:2014-04-09 05:42:26

标签: scala spray spray-json

我希望能够使用spray-json在Scala中创建case类,但在类中定义asJson方法,但我似乎无法弄清楚如何。例如,我希望能够这样做:

case class Foo(bar: String) {
  def toJson: JsValue = ...
}

创建隐式JSON转换器很容易:

object JsonProtocols extends DefaultJsonProtocol {
  implicit val fooFormat = jsonFormat1(Foo)
}

但据我所知,这只能在课外进行。我很想找到一种在类本身中声明JSON格式转换为JSON的方法。

1 个答案:

答案 0 :(得分:3)

你可以想象这样做:

scala> import spray.json._
import spray.json._

scala> case class Foo(bar: String) {
  def toJson:JsValue = JsObject( "bar" -> JsString(bar) )
}
defined class Foo

scala> Foo("bar").toJson
res2: spray.json.JsValue = {"bar":"bar"}

到目前为止一直很好,但这并不适合Spray的类型类机制。例如,如果您尝试将Foo转换为JsValue(例如使用路由entity( as[Foo] ) { ... }),则Spra​​y的路由DSL会给您一个类型错误。他们已经为你准备的暗示,对于像List和Set这样的类型,也不能与Foo合作:

scala> import DefaultJsonProtocol._
import DefaultJsonProtocol._

scala> List(Foo("bar")).toJson
<console>:31: error: Cannot find JsonWriter or JsonFormat type class for List[Foo]
              List(Foo("bar")).toJson

因为没有JsonFormat类可以用来转换Foo,就像JsonFormat1(Foo)创建的那样。

您可能会考虑将格式放在Foo伴随对象中,因为范围内的类伴随对象位于隐式搜索路径上,如下所示:

object Foo extends DefaultJsonProtocol {
  implicit val fooFormat = jsonFormat1(Foo)
}
case class Foo(bar: String)

但是因为我们还没有完成定义Foo,编译器给我们一个类型错误:

[error]  found   : Foo.type
[error]  required: ? => ?
[error]  Note: implicit value fooFormat is not applicable here because it comes after the application point and it lacks an explicit result type

添加显式结果类型RootJsonFormat[Foo]并不能解决问题:

[error]  found   : Foo.type
[error]  required: ? => Foo
[error]   implicit val fooFormat:RootJsonFormat[Foo] = jsonFormat1(Foo)

技巧(感谢knutwalker!)是明确传递Foo.apply

object Foo extends DefaultJsonProtocol {
  implicit val fooFormat = jsonFormat1(Foo.apply)
}
case class Foo(bar: String)