2

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これはコンパイルされません。結果に値を追加して を生成することを検討しましたが、私が見つけたものはかなり悪く見え言語メンテナーはそれを実装しませんFoounapplyTuple2Tuple3

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

助言がありますか?

値が JSON に存在しないが、結果のオブジェクトによって指定されている場合に値を提供して、別の方向に進むことができることに注意してください。Reads.pure

4

2 に答える 2

3

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

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であり、必要なものを追加できる独自の関数に置き換えることができます。

さらにきれいな構文が本当に必要な場合は、 Shapelessを使用できます。

import shapeless.syntax.std.tuple._

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

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

于 2014-04-11T18:34:45.967 に答える
1

unapplyもう 1 つのオプションは、追加の値を返すを実装するオブジェクト ビルダーを使用することです。これにより、書き込みがよりクリーンになりますが、新しいオブジェクトが追加されます。apply メソッドと 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))
于 2014-09-26T05:22:54.117 に答える