Play の (2.2) Scala JSON コンビネーターを使用して Case クラスに見つからない任意の値を書き込む

StackOverflow https://stackoverflow.com//questions/23019485

質問

を実装したいのですが、 Writes シリアル化されているクラスで見つからない JSON オブジェクトを出力します。

ケースクラスの場合:

case class Foo(i:Int, s:String)

私は生産しようとしています:

{
  "i": <int>,
  "s": "<string>",
  "other": "Some value."
}

素朴な最初の試みは次のとおりです。

val writes: Writes[Foo] = ((
  (__ \ "i").write[Int] and
    (__ \ "s").write[String] and
    (__ \ "other").write("Some value.")
  )(unlift(Foo.unapply))

当然のことながら、これは後続のものとしてコンパイルされません。 and 呼び出しは CanBuild3 そして Fooさんの unapply を生成します Tuple2. 。結果に値を追加して、 Tuple3, 、しかし私が見つけたこと かなり悪そうに見える そしてその 言語管理者はそれを実装しないでしょう.

これを回避する方法はありますが、結果として得られる JSON に追加するデコレータ値でモデル クラスを汚染したくありません。

助言がありますか?

あなたに注目する価値があります できる 別の方向に進み、次の値を提供します Reads.pure 値が JSON に存在しないが、結果として得られるオブジェクトによって指定される場合。

役に立ちましたか?

解決

少し脱糖することで、これを非常に簡単に行うことができます。

val writes: Writes[Foo] = (
  (__ \ "i").write[Int] and
  (__ \ "s").write[String] and
  (__ \ "other").write[String]
)(foo => (foo.i, foo.s, "Some value."))

unlift(Foo.unapply) から関数を取得するための単なる派手な方法です Foo 前述の適用ビルダー式で必要な種類のタプルに変換し、必要なものを追加できる独自の関数に置き換えることができます。

もし、あんたが 本当に さらにきれいな構文が必要な場合は、次を使用できます 形のない:

import shapeless.syntax.std.tuple._

val writes: Writes[Foo] = (
  (__ \ "i").write[Int] and
  (__ \ "s").write[String] and
  (__ \ "other").write[String]
)(_ :+ "Some value.")

美しいですが、やりすぎかもしれません。

他のヒント

別のオプションは、追加値を返すunapplyを実装するオブジェクトビルダーを使用することです。これにより、書き込みがクリーナーになりますが、新しいオブジェクトを追加します。適用方法と未申成方法の両方が最終的なオブジェクトへの追加マッサージに使用できるため、これを有用しました(例: HTTPS://stackoverflow.com/a/22504468/1085606

例:

case class Foo(i: Int, s: String)

object FooBuilder {
  def unapply(foo: Foo): Option[(Int, String, String)] = {
    Some((foo.i, foo.s, "Some extra value"))
  }
}

val writes: Writes[Foo] = ((
  (__ \ "i").write[Int] and
    (__ \ "s").write[String] and
    (__ \ "other").write[String]
  )(unlift(FooBuilder.unapply))
.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top