いくつかのケースクラスを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] ^
私は知っています...文字列だけを含むケースクラスはあまり意味がありません...しかし、外部ライブラリからのものと非常によく似たケースクラスをシリアル化/逆シリアル化する必要があります。
何か案が?私は何かが足りないのですか?どんな助けでも本当にありがたいです...私は夢中になっています:-(ありがとう。
Jsonコンビネータは、Play 2.1の単一フィールドケースクラスでは機能しません(2.2で可能になるはずです)
Pascal(このAPIの作成者)はこの状況をここで説明しています https://groups.google.com/forum/?fromgroups=#!starred/play-framework/hGrveOkbJ6
このように機能するいくつかの回避策があります:
case class MyType(value: String)
val myTypeRead = (__ \ 'value).read[String].map(v => MyType(v)) // covariant map
ps:type
はScalaのキーワードであり、パラメーター名として使用することはできません(ただし、この例のためだけだと思います)
編集:この回避策は、play2.3.Xではまだ必要ありません。マクロは正常に機能します。
問題は、(私が知る限り)Play2.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))
あなたの場合、and
メソッドを使用できないため(値は1つしかない)、FunctionalBuilder#CanBuildX
のNiceapply
関数(Xは1〜22)にアクセスできません。 )。
同様のものを提供するために、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))
未使用のフィールドをケースクラスに追加するだけではどうでしょうか。適切なコメントを付けるか、自明のフィールド名を使用してください。
//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 _)
}