2013-08-26 67 views
16

我經常需要序列化/反序列化和類型(如Either[S,T]),我還沒有找到一個通用或優雅的方式來做到這一點。下面是一個例子類型(基本等同於EitherJSON序列化在斯卡拉玩多個案例類(和類型)特質

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

對我很好。你可以更新你的最佳努力來玩2.5嗎?謝謝! – qed

+0

沒關係,我發現如何在play2.5中做到這一點,並把它放在答案中。 – qed

回答

0

我認爲這是一樣簡單,你可以把它,如果你想避免編寫代碼爲每個明確的亞型,也許你可以使用反射做,直接使用傑克遜或反射一些其他的JSON庫支持。或者編寫自己的宏來從子類型列表中生成格式。

0

我對我的json酸洗庫Prickle中序列化sum-types問題有系統的解決方案。類似的想法可以用於Play。仍有需要一些配置代碼,但其高的信號/噪聲,例如最終的代碼,如:用超類型相關聯

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

CompositePicklers被配置爲與一個PicklerPair每個已知亞型(即總和類型選項)。關聯在配置時設置。

pickling期間,描述符被髮送到描述記錄的哪個子類型的json流中。

unpickling,描述信息讀出JSON,然後用來定位合適的Unpickler的亞型

0

一個例子更新的遊戲2.5:

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]) 
}