14

いくつかのケース クラスを Json との間でシリアライズ/デシリアライズしようとしています... フィールドが 1 つだけのケース クラスを扱うときに問題があります (私は Play 2.1 を使用しています):

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

case class MyType(type: String)

object MyType {

  implicit val myTypeJsonWrite = new Writes[MyType] {
    def writes(type: MyType): JsValue = {
      Json.obj(
        "type" -> MyType.type
      )
    }
  }

  implicit val myTypeJsonRead = (
    (__ \ 'type).read[String]
  )(MyType.apply _)
}

上記のコードは、常に次のエラー メッセージを生成します。

[error] /home/j3d/Projects/test/app/models/MyType.scala:34: overloaded method value read with alternatives:
[error]   (t: String)play.api.libs.json.Reads[String] <and>
[error]   (implicit r: play.api.libs.json.Reads[String])play.api.libs.json.Reads[String]
[error]  cannot be applied to (String => models.MyType)
[error]     (__ \ 'method).read[String]
[error]                        ^

私は知っています...文字列だけを含むケースクラスはあまり意味がありません...しかし、外部ライブラリから取得した上記のケースクラスと非常によく似たケースクラスをシリアル化/逆シリアル化する必要があります。

何か案が?何か不足していますか?どんな助けでも本当に感謝しています...私は夢中になっています:-(ありがとう。

4

3 に答える 3

23

Json コンビネータは、Play 2.1 の単一フィールド ケース クラスでは機能しません (2.2 では可能になるはずです)。

Pascal (この API の作成者) は、この状況をここで説明しています https://groups.google.com/forum/?fromgroups=#!starred/play-framework/hGrveOkbJ6U

次のようないくつかの回避策があります。

case class MyType(value: String)
val myTypeRead = (__ \ 'value).read[String].map(v => MyType(v)) // covariant map

ps:typeは Scala のキーワードであり、パラメーター名として使用することはできません (ただし、この例のためだけだと思います)

編集: この回避策は、play 2.3.X ではまだ必要ありません。マクロは正常に動作します。

于 2013-02-23T17:04:54.270 に答える
4

問題は、(私が知る限り) Play 2.1 フレームワークは から始まるタプルのみを処理することTuple2です。例では、次のように使用されています。

case class CaseClass(key1: String, key2: String)
object CaseClass {
  implicit val caseClassFormat = {
    val jsonDescription =
      (__ \ "key1").format[String] and (__ \ "key2").format[String]

    jsonDescription(CaseClass.apply _, unlift(CaseClass.unapply))
  }
}

そして、それを使用するには

val caseClassJson = Json.toJson(CaseClass("value1", "value2"))

println(caseClassJson)
println(Json.fromJson[CaseClass](caseClassJson))

あなたの場合、メソッドを使用することはできません(値は1つしかない)ため、 (Xは1から22です)の素晴らしい機能にandアクセスできません。applyFunctionalBuilder#CanBuildX

似たようなものを提供するために、niceメソッドbuildと同様のシグネチャを持つメソッドを提供する暗黙のクラスを作成できます。apply

implicit class FormatBuilder[M[_], A](o: M[A]) {
  def build[B](f1: A => B, f2: B => A)(implicit fu: InvariantFunctor[M]) =
    fu.inmap[A, B](o, f1, f2)
}

ケースクラスを次のように調整できるようになりました

case class MyType(tpe: String)

object MyType {
  implicit val myTypeFormat =
    ((__ \ "type").format[String]) build (MyType.apply _, unlift(MyType.unapply))
}

次に、このように使用できます

val myTypeJson = Json.toJson(MyType("bar"))

println(myTypeJson)
println(Json.fromJson[MyType](myTypeJson))
于 2013-02-23T17:13:28.717 に答える
0

ケースクラスに未使用のフィールドを追加するだけではどうですか。まともなコメントを入れるか、自明なフィールド名を使用してください。

//f2 is unused field for de/serialization convenience due to limitation in play

case class SingleField(f1: String, f2: Option[String]) 
object SingleField {
   implicit val readSingleField : Reads[SingleField] = (
        (__ \ "f1").read[String] and 
           (__ \ "f2").readNullable[String])(SingleField.apply _)  
}
于 2017-08-24T09:13:28.133 に答える