2013-08-26 10 views
16

sum型をシリアル化/逆シリアル化する必要があります(Either[S,T]など)。ここで(Eitherと本質的に同等)の例タイプScalaのPlayで複数のケースクラス(Sum型)を持つJsonシリアライゼーション

sealed trait OutcomeType 
case class NumericOutcome(units: String)    extends OutcomeType 
case class QualitativeOutcome(outcomes: List[String]) extends OutcomeType 

だ。ここのシリアル化を実装コンパニオンオブジェクトで私のベストエフォートです。それはうまくいきますが、すべての和型についてこれらのことを何度も繰り返し書くことは非常に面倒です。それをより良く、より一般的にするための提案はありますか?

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

object OutcomeType { 

    val fmtNumeric  = Json.format[NumericOutcome] 
    val fmtQualitative = Json.format[QualitativeOutcome] 

    implicit object FormatOutcomeType extends Format[OutcomeType] { 
    def writes(o: OutcomeType) = o match { 
     case [email protected](_)  => Json.obj("NumericOutcome"  -> Json.toJson(n)(fmtNumeric)) 
     case [email protected](_) => Json.obj("QualitativeOutcome" -> Json.toJson(q)(fmtQualitative)) 
    } 

    def reads(json: JsValue) = (
     Json.fromJson(json \ "NumericOutcome")(fmtNumeric) orElse 
     Json.fromJson(json \ "QualitativeOutcome")(fmtQualitative) 
    ) 
    } 
} 
+0

あなたはjson4s HTTPを試してみました/json4s.org? また、遊びで使用したい場合は、https://github.com/tototoshi/play-json4s をご覧になるか、自分で実装してください。 –

+0

いいですね。あなたはplay2.5へのあなたの最善の努力を更新できますか?ありがとう! – qed

+0

心配しないで、私はplay2.5でこれを行う方法を見つけて答えに入れました。 – qed

答えて

0

私は反射で直接、または他のいくつかのJSONライブラリジャクソンを使用し、あなたはそれぞれの明示的なサブタイプのコードを書き込まないようにしたい場合は、多分あなたが反射でそれを行うことができ、それはあなたがそれを作ることができると同じくらいシンプルだと思いますサポート。または、サブタイプのリストからフォーマットを生成する独自のマクロを作成します。

0

私は、私のjson酸洗ライブラリPrickleのsum-typesをシリアライズする問題の体系的な解決法を持っています。 Playでも同様の考えを採用することができます。例えば、高い信号/ノイズは、そこに必要ないくつかのコンフィギュレーションコードがまだあるが、最終的なコードのような:スーパータイプに関連付けられ

implicit val fruitPickler = CompositePickler[Fruit].concreteType[Apple].concreteType[Lemon]

CompositePicklersが既知の各サブタイプに対して1つPicklerPair(すなわち和型オプション)で構成されています。このアソシエーションは、設定時に設定されます。

picklingの間に、レコードがどのサブタイプであるかを記述する記述子がjsonストリームに出力されます。 unpickling中に

、記述子はJSONの読み出し、サブタイプ

0

プレイ2.5用の更新たとえば、適切なUnpicklerの位置を特定するために使用される:/:

object TestContact extends App { 

    sealed trait Shape 

    object Shape { 
    val rectFormat = Json.format[Rect] 
    val circleFormat = Json.format[Circle] 

    implicit object ShapeFormat extends Format[Shape] { 
     override def writes(shape: Shape): JsValue = shape match { 
     case rect: Rect => 
      Json.obj("Shape" -> 
      Json.obj("Rect" -> 
       Json.toJson(rect)(rectFormat))) 
     case circle: Circle => 
      Json.obj("Shape" -> 
      Json.obj("Circle" -> 
       Json.toJson(circle)(circleFormat))) 
     } 

     override def reads(json: JsValue): JsResult[Shape] = { 
     json \ "Shape" \ "Rect" match { 
      case JsDefined(rectJson) => rectJson.validate[Rect](rectFormat) 
      case _ => json \ "Shape" \ "Circle" match { 
      case JsDefined(circleJson) => circleJson.validate[Circle](circleFormat) 
      case _ => JsError("Not a valide Shape object.") 
      } 
     } 
     } 
    } 

    } 

    case class Rect(width: Double, height: Double) extends Shape 

    case class Circle(radius: Double) extends Shape 

    val circle = Circle(2.1) 
    println(Json.toJson(circle)) 
    val rect = Rect(1.3, 8.9) 
    println(Json.toJson(rect)) 

    var json = Json.obj("Shape" -> Json.obj("Circle" -> Json.obj("radius" -> 4.13))) 
    println(json.validate[Shape]) 
    json = 
    Json.obj("Shape" -> 
     Json.obj("Rect" -> 
     Json.obj("width" -> 23.1, "height" -> 34.7))) 
    println(json.validate[Shape]) 
} 
関連する問題