2

Spray-json を使用して Scala でケース クラスを作成できるようにしたいのですがasJson、 class でメソッドを定義しますが、方法がわかりません。たとえば、私はこれを行うことができるようにしたいと思います:

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

暗黙的な JSON コンバーターを作成するのは簡単です。

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

しかし、私の知る限り、これはクラスの外でのみ行うことができます。JSON 形式を宣言し、クラス内で JSON に変換する方法を見つけたいと思っています。

4

1 に答える 1

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 の型クラス メカニズムには適合しません。たとえば、Spray のルーティング DSL では、Foo を JsValue との間で変換しようとすると (たとえば route を使用してentity( as[Foo] ) { ... })、型エラーが発生します。また、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

作成されたもののように、Foo を変換するために使用する JsonFormat クラスがないため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)
于 2014-04-09T06:39:59.050 に答える