2017-06-24 3 views
1

は、私の目標は、次のモデルにJSONを変換することです:キルケ:異なる可能なコンテンツタイプとコンテナタイプをデコード

case class Container(typeId: Int, timestamp: Long, content: Content) 

sealed trait Content 
case class ContentType1(...) extends Content 
case class ContentType2(...) extends Content 
case class ContentType3(...) extends Content 
  • その構造は常に同じに見えるコンテナタイプがあります。
  • コンテナのcontentは、(アトリビュートの量とタイプに関して)全く違って見えるタイプで表されます。ただし、すべてのコンテンツタイプはコンパイル時に認識され、密閉された特性を実装します。
  • コンテナのtypeId属性はコンテンツタイプを示します。例えば。 Nの値はcontentContentTypeNのタイプであることを意味します。
  • JSON構造は、あなたが期待するように見え、上記のScala型に直接マッピングします。
  • (Btw:これはより洗練されたソリューションであれば、コンテナタイプをContainer[A <: Content]に変更するために公開されています)。

これをcirceでデコードするにはどうすればよいでしょうか?この場合、自動デコードは機能しません。

編集:JSON構造のドキュメントは?mixed (object, integer, bool)としてコンテンツフィールドを説明し、それはまた、簡単なIntまたはその代わりにケースクラスオブジェクトのBooleanすることができます。しかし、今のところ、これらの2つのタイプを無視することは大丈夫でしょう(そのための解決策があるのはいいでしょう)。

答えて

0

私はsemiauto(deriveDecoder付き)、validateおよびorを使用します。

case class Container[+C](typeId: Int, timestamp: Long, content: C) 

sealed trait Content 
@JsonCodec case class ContentType1(...) extends Content 
@JsonCodec case class ContentType2(...) extends Content 

object Content { 
    import shapeless._ 
    import io.circe._ 
    import io.circe.generic.semiauto._ 

    def decodeContentWithGuard[T: Decoder](number: Int): Decoder[Content[T]] = { 
    deriveDecoder[Content[T]].validate(_.downField("typeId") == Right(number), s"wrong type number, expected $number") 
    } 

    implicit val contentDecoder: Decoder[Container[Content]] = { 
    decodeWithGuard[ContentType1](1) or 
    decodeWithGuard[ContentType2](2) 
    } 
} 

あなたは共変注釈をしたくない場合は、Contentに、内側ContentTypeXをマッピングし、アップキャストする必要があります。

おそらくジェネリックのない解決策もありますが、セミオートは使用できません。

コンパイルしていない可能性があります。テストしませんでした。

関連する問題