2

ジェネリック型 T を持つ関数を定義したいのですが、T には特定のメソッドの暗黙的な実装があります。

実際、私は次のことを達成しようとしています:

次のような非常に反復的なコードがあります。

def update(id: Long) = CORSAction { implicit request =>
  request.body.asJson.map { json =>
    json.asOpt[Wine].map { wine =>
      wine.copy(id=Id(id)).update.fold(
        errors => JsonBadRequest(errors),
        wine => Ok(toJson(wine).toString)
      )
    }.getOrElse       (JsonBadRequest("Invalid Wine entity"))
  }.getOrElse         (JsonBadRequest("Expecting JSON data"))
}

そのため、有効な json かどうかを確認してから解析することは、関数にカプセル化したい非常に一般的なタスクです。

wine タイプについては、json から解析し、json としてワイン オブジェクトをレンダリングする書き込みおよび読み取りメソッドを実装する暗黙的な JsonWineFormatter を定義しました。

object WineFormatter {

  implicit object JsonWineFormatter extends Format[Wine] {

    def writes(o: Wine): JsValue = {
      toJson( Map(
        "id"          -> toJson(o.id),
    [...]

    def reads(j: JsValue): Wine = {
      Wine(
        id = (j \ "id").as[Option[Pk[Long]]] 
    [...]

だから私はこのようなジェネリックメソッドを定義しようとしています:

def parse[T](implicit request: Request[AnyContent]): Option[T] = {
  request.body.asJson.map { json =>
    json.asOpt[T].map { entity =>
      entity
    }
  }
}

しかし、次のエラーが発生します。

T 型の Json デシリアライザーが見つかりません。この型の暗黙の Reads または Format を実装してみてください。

ジェネリック型 T のニーズと暗黙の読み取りを指定する必要があります...

それを達成する方法を知っていますか?

--

編集:私は次のことを試しました:

import play.api.libs.json.JsValue
type EntityWithJsonFormatter[T] = T {def reads(j: JsValue): T}

def parse[T: EntityWithJsonFormatter](request: Request[AnyContent]): Option[T] = {
  request.body.asJson.map { json =>
    json.asOpt[T].map { entity =>
      entity
    }
  }
}

しかし明らかに、読み取りを実装するのは T ではなく、代わりにそれを実装する暗黙のオブジェクトが必要です。それを型で指定する方法がわかりません...

4

1 に答える 1

4

JsValueドキュメントでは次のasOptように定義されています。

def asOpt [T] (implicit fjs: Reads[T]): Option[T] 

もしあなたimport play.api.libs.json.Reads

def parse[T: Reads]( ...

トリックを行う必要があります。

于 2012-08-24T04:48:38.070 に答える