これを行うことを想像できます:
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)