17

合計型 ( など) をシリアル化/逆シリアル化する必要があることがよくありますがEither[S,T]、それを行うための一般的またはエレガントな方法をまだ見つけていません。これがタイプの例です(本質的には と同等ですEither

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 n@NumericOutcome(_)     => Json.obj("NumericOutcome"     -> Json.toJson(n)(fmtNumeric))
      case q@QualitativeOutcome(_) => Json.obj("QualitativeOutcome" -> Json.toJson(q)(fmtQualitative))
    }

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

3 に答える 3

1

明示的なサブタイプごとにコードを記述したくない場合は、リフレクションを使用して、jackson を直接使用するか、リフレクションをサポートする他の json ライブラリを使用できます。または、独自のマクロを作成して、サブタイプのリストから Format を生成します。

于 2013-08-27T14:58:48.530 に答える
0

json 酸洗ライブラリPrickleで合計型をシリアル化する問題に対する体系的な解決策があります。Play でも同様のアイデアを採用できます。まだいくつかの設定コードが必要ですが、信号/ノイズが高くなります。たとえば、最終的なコードは次のようになります。

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

スーパータイプに関連付けられたCompositePicklersPicklerPairは、既知のサブタイプ (合計タイプ オプション) ごとに 1 つ構成されます。関連付けは構成時にセットアップされます。

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

unpickling中に、記述子が json から読み取られUnpickler、サブタイプに適した場所を特定するために使用されます

于 2015-11-30T10:23:27.593 に答える