2

Json からケース クラス (およびその逆) への多くのマッピングを含むストライプ用の API を作成しようとしています。最終的に a になるという問題に遭遇しましたList[JsResult[A]](これは、JObject のリストを介してマッピングし、それらに対していくつかの操作を実行して、それらを適切なケース クラスにマップした結果です)。問題のコードは以下です

case class Sources(data: List[PaymentSource],
                     hasMore: Boolean,
                     totalCount: Double,
                     url: String)

  implicit val sourcesReader: Reads[Sources] = {

    val dataAsList = (__ \ "data").read[List[JsObject]].flatMap{jsObjects =>
      val `jsResults` = jsObjects.map{jsObject =>
        val `type` = jsObject \ "type"

        val paymentSource: JsResult[PaymentSource] = `type` match {
          case JsString("card") =>
            Json.fromJson[Card](jsObject)
          case JsString("bitcoin_receiver") =>
            Json.fromJson[BitcoinReceiver](jsObject)
          case JsString(s) =>
            throw UnknownPaymentSource(s)
          case _ =>
            throw new IllegalArgumentException("Expected a Json Object")
        }

        paymentSource
      }

      jsResults

    }

jsResults のタイプは ですがList[JsResult[A]]、読み取りで適切に構成するには、 aJsResult[A]または a のいずれかを返す必要がありJsErrorます。

Json.fromJson[Card](jsObject).getの代わりに実行することもできますがJson.fromJson[Card](jsObject)、そうすることは、Play Json で累積的なエラー処理を失うことを意味します (エラーをランタイムにプッシュすることも意味します)。

4

3 に答える 3

3

を使用できますReads.list()

val paymentSourceReader: Reads[PaymentSource] = __.read[JsObject].flatMap { o =>
  (__ \ "type").read[String].collect(ValidationError("UnknownPaymentSource")) {
    case "card" =>
      o.as[Card]
    case "bitcoin_receiver" =>
      o.as[BitcoinReceiver]
  }
}
  1. read[String]プロパティがない場合はエラーを作成しますtype
  2. collect(ValidationError("UnknownPaymentSource")タイプが !(card|bitcoin_receiver) の場合はエラーを作成します。
  3. o.as[...]キャストできない場合は例外をスローします

次に、「paymentSourceReader」を使用します

val dataReader: Reads[List[PaymentSource]] = (__ \ "data").read[List[PaymentSource]](Reads.list(paymentSourceReader))

dataReaderReads[PaymentSource]コンビネータ forSourcesまたはjson.reads(dataReader)forを使用して複雑なリーダーで使用できますJsResult[List[PaymentSource]]

于 2016-02-10T05:28:34.487 に答える
2

複数の成功結果がある場合はどうなるでしょうかList[JsResult[A]]JsResult[A]これは、 に対して複数の値があることを意味しますA。あなたはそれをに変えることができJsResult[List[A]]ます.これを行うにはいくつかの方法があります.私はおそらくこれを行うでしょう:

val allErrors = jsResults.collect {
  case JsError(errors) => errors
}.flatten

val jsResult = if (allErrors.nonEmpty) {
  JsError(allErrors)
} else {
  JsSuccess(jsResults.collect {
    case JsSuccess(a, _) => a
  })
}
于 2016-02-10T03:52:28.943 に答える
0

同様の問題がありました。JsSuccess で 2 つの JsResults を結合したかったのです。tupledそしてand、私がこの任務を遂行するのを助けてくれました。どちらもplay.api.libs.functionalパッケージの一部です。

JsResultこれは、2 つを 1 つに結合する方法です。

import play.api.libs.json._
import play.api.libs.functional.syntax._

((__ \ 'id).validate[Long] and (__ \ 'name).validate[String]).tupled 
    match {
      case JsSuccess((id,name),_) => ...
      case err: JsError =>
于 2016-12-05T05:35:29.253 に答える