1

私は初心者であり、scala/play であり、playframework の JSON の読み取り/書き込みについて助けが必要です。

Json.reads[T] および Json.writes[T] マクロを使用して、クラスの json の読み取りと書き込みを定義します。ただし、1 つのプロパティ名を (常に) 異なる方法でマッピングしたいと考えています。つまり、クラスで名前が付けられたプロパティがあり、オブジェクトがjsonに変換されたとき、またはその逆に変換されたときにidそれを表現したいと考えています。_id

これを達成するために Json.reads および Json.writes マクロによって生成された読み取り/書き込みオブジェクトを変更する方法はありますか、または 1 つのプロパティを別の名前にするためだけに読み取りと書き込みを手動で書き直す必要がありますか?

編集

問題をよりよく説明してみましょう。モデルオブジェクト User を考えてみましょう:

case class User (id: BigInt, email: String, name: String)

REST API のコンテキストで json を提供する目的で User を json にシリアル化する場合、json は次のようになります。

{ "id": 23432, "名前": "ジョー", "メール: "joe@example.com" }

MongoDB json からの保存/更新/読み取りの目的で User を json にシリアル化する場合、次のようになります。

{ "_id": 23432, "名前": "ジョー", "メール: "joe@example.com" }

idつまり、Mongo との通信をとして表す必要がある場合を除いて、すべて同じ_idです。

Darcy Qiu の回答で提案されているように、モデル オブジェクトごとに 2 セットの読み取りと書き込み (1 つは Web 用、もう 1 つは Mongo との通信用) を手動で記述できることはわかっていますが、2 セットの読み取りと書き込みはほぼ維持されています。 id プロパティを除いて同一であるため、コードの重複が多いように思われるため、より良いアプローチがあるかどうか疑問に思っています。

4

3 に答える 3

1

最初に、名前変更 id/_id を前後に変換するための変換を定義します。

import play.api.libs.json._
import play.modules.reactivemongo.json._

val into: Reads[JsObject] = __.json.update( // copies the full JSON
  (__ \ 'id).json.copyFrom( (__ \ '_id).json.pick ) // adds id
) andThen (__ \ '_id).json.prune  // and after removes _id

val from: Reads[JsObject] = __.json.update( // copies the full JSON
  (__ \ '_id).json.copyFrom( (__ \ 'id).json.pick ) // adds _id
) andThen (__ \ 'id).json.prune  // and after removes id

(なぜ変換なのかを理解するには、 httpsReads ://www.playframework.com/documentation/2.4.x/ScalaJsonTransformers をお読みください)

マクロが生成さWritesReads、エンティティ クラスが次のようになっているとします。

def entityReads: Reads[T] // eg Json.reads[Person]
def entityWrites: Writes[T] // eg Json.writes[Person]

次に、変換をマクロで生成されたコードと組み合わせます。

private[this] def readsWithMongoId: Reads[T] = 
  into.andThen(entityReads)
private[this] def writesWithMongoId: Writes[T] =
  entityWrites.transform(jsValue => jsValue.transform(from).get)

最後のもの。Mongo ドライバーは、挿入する json が JsObject であることを確認したいと考えています (タイプセーフであること)。そのため、 が必要OWritesです。私はより良い方法を見つけていません:

private[this] def oWritesWithMongoId = new OWrites[T] {
  override def writes(o: T): JsObject = writesWithMongoId.writes(o) match {
    case obj: JsObject => obj
    case notObj: JsValue => 
      throw new InternalError("MongoRepo has to be" +
      "definded for entities which serialize to JsObject")
  }

}

最後のステップは、暗黙の を提供することOFormatです。

implicit val routeFormat: OFormat[T] = OFormat(
  readsWithMongoId,
  oWritesWithMongoId
)
于 2015-09-04T10:33:30.007 に答える