3

を読み込み、Reads[JsObject]の束を動的に生成します。これはSeq[Reads[JsObject]]にあります。これらのすべてを実際に適用するにはReads[JsObject]andとマージして一つのReads[JsObject]にする必要があります。これは可能ですか?JSONを再生する:Seq [JsObject]を読み込み[JsObject]

私は(例)を持っている

val generatedReads: Seq[Reads[JsObject]] = Seq(
    (__ \ "attr1").json.copyFrom((__ \ "attr1" \ "attr1a").json.pick), 
    (__ \ "attr2").json.pickBranch 
) 

私は必要なもの:

val finalReads: Reads[JsObject] = 
    (__ \ "attr1").json.copyFrom((__ \ "attr1" \ "attr1a").json.pick) and 
    (__ \ "attr2").json.pickBranch 

プロパティ名とその支店選ぶためにそれが持っている理由です、コンパイル時に知られていません動的である。

答えて

3

これはかなり一般的な質問です。この回答はReads.traversableReads[F[_], A]に触発されています。

Reads[A]という累積の考え方をサポートするには、あなたのすべてのGenererated Reads[JsObject]を試してみて、[エラー、Vector [JsObject]]のいずれかを使用します。元の 'Reads.traversableReads [F [_]、A]'はReads[List[A]]または何らかのコレクションを返しますが、単純なJsonが必要です。問題ありません。++JsObjectsをconcatinatesします。


def reduceReads(generated: Seq[Reads[JsObject]]) = Reads {json => 
    type Errors = Seq[(JsPath, Seq[ValidationError])] 

    def locate(e: Errors, idx: Int) = e.map { case (p, valerr) => (JsPath(idx)) ++ p -> valerr } 

    generated.iterator.zipWithIndex.foldLeft(Right(Vector.empty): Either[Errors, Vector[JsObject]]) { 
    case (acc, (r, idx)) => (acc, r.reads(json)) match { 
     case (Right(vs), JsSuccess(v, _)) => Right(vs :+ v) 
     case (Right(_), JsError(e)) => Left(locate(e, idx)) 
     case (Left(e), _: JsSuccess[_]) => Left(e) 
     case (Left(e1), JsError(e2)) => Left(e1 ++ locate(e2, idx)) 
    } 
    } 
    .fold(JsError.apply, { res => 
     JsSuccess(res.fold(Json.obj())(_ ++ _)) 
    }) 
} 

scala> json: play.api.libs.json.JsValue = {"attr1":{"attr1a":"attr1a"},"attr2":"attr2"} 

scala> res7: play.api.libs.json.JsResult[play.api.libs.json.JsObject] = JsSuccess({"attr1":"attr1a","attr2":"attr2"},) 

新しい素晴らしい単純な答えは、数日後、私はこの素晴らしいアイデアを持っていました。 object Readsは暗黙的にReducer[JsObject, JsObject]ですので、Seq(Reads[JsObject])FunctionalBuilderand、次にreduce)に減らすことができます。

def reduceReads(generated: Seq[Reads[JsObject]]) = 
    generated.foldLeft(Reads.pure(Json.obj())){ 
    case (acc, r) => 
     (acc and r).reduce 
    } 

この解決策は簡単で明確です。オリジナルのアイデアはSeq(Reads[JsObject]) => Seq(JsResult[JsObject]) => Reads[JsObject]マッピングをベースにしていますが、最後の一般的Seq(Reads[JsObject]) => Reads[JsObject]


基本的なJSONコンビネータの原則に基づいて、問題が解決しますが、タスク自体は正しくないです。読み込みを制御しない場合は、同じパスが2回使用されるかどうかを確認します。

+0

私はそれを完全には理解していませんが、間違いなく私が望んだことは間違いありません。確かに、コードを使って遊ぶほど、私はそれを理解します。ありがとう! – Nick

関連する問題