4

スプレーとスプレー json を使用して json POST 本文を解析するための汎用エクストラクターを作成しようとしています。

ただし、複数のモデルで動作させるのに苦労しています。サービス オブジェクトの case ステートメントは次のとおりです。

import MyJsonProtocol._

...

def receive = {
  case Post (Routes.person.post, p: Person) => sender ! Ok(Actions.person.post(p))
  case Get  (Routes.foo.forId(x))           => sender ! Ok(x)
  case _                                    => sender ! Ok("No handler")
}

そして、これが私が書いたエクストラクタです (これは、case ステートメントのスコープ内に単一のモデルの JsonReader しかない限り機能します):

//NB. Json.parse returns an Option[T]
object Post extends Request {
  def unapply[T:JsonReader](req: HttpRequest): Option[(String, T)] = req match {
    case HttpRequest(POST, url, _, HttpBody(_, body), _) => Json.parse[T](body.asString).map((url, _))
    case _ => None
  }
}

ただし、新しいモデル (および関連する JsonReader) を追加するとすぐに、コードは次のエラーでコンパイルされなくなります。

ambiguous implicit values:
[error]  both value personFormat in object Json of type => spray.json.RootJsonFormat[com.rsslldnphy.foam.models.Person]
[error]  and value animalFormat in object Json of type => spray.json.RootJsonFormat[com.rsslldnphy.foam.models.Animal]
[error]  match expected type spray.json.JsonReader[T]
[error]     case Post (Routes.person.post, p: Person) => sender ! Ok(Actions.person.post(p))

JsonReaders のジェネリック型が異なるという事実は失われているようです。このタイプの消去はありますか?私が欲しいものを手に入れる方法はありますか?

これまでのところ、プロジェクトの完全なコンパイル コードと、ExampleService何が壊れているのかを説明するコメントがあります: github.com/rsslldnphy/foam。あなたの助けに感謝します、ありがとう。

または、私が望むことが現在不可能な場合、誰かが別のアプローチを提案できますか?

4

1 に答える 1

2

これを機能させるには、コンパイラに明示的な指示を与える必要があります。以下に示すように、コンパイラが T が何であるべきかを推測する方法はありません。コンパイラは、リクエストからJsonを動的に見て、それからタイプを暗示できる必要があります(これを行うことを夢見ることしかできません;))

def unapply[T:JsonReader](req: HttpRequest): Option[(String, T)] = (...) Json.parse[T] (...)

つまり、これを機能させるには、以下に示すように投稿に明示的に注釈を付ける必要があります。

import MyJsonProtocol._

...

def receive = {
  case Post[Person] (Routes.person.post, p: Person) => sender ! Ok(Actions.person.post(p))
  case Get  (Routes.foo.forId(x))           => sender ! Ok(x)
  case _                                    => sender ! Ok("No handler")
}

定義をこれに変更します

case class Post[T: JsonReader] extends Request {
  def unapply(req: HttpRequest): Option[(String, T)] = req match {
    case HttpRequest(POST, url, _, HttpBody(_, body), _) => Json.parse[T](body.asString).map((url, _))
    case _ => None
  }
}
于 2012-11-13T21:47:39.880 に答える