我希望能够使用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的方法。
答案 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] ) { ... }
),则Spray的路由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)