0
import argonaut._
import Argonaut._
import ArgonautShapeless._
sealed trait Parent
case class Foo(x: Int) extends Parent
case class Bar(y: String) extends Parent
我試圖定義DecodeJson[Parent]
:
implicit val parentDecodeJson: DecodeJson[Parent] =
DecodeJson(c => c.focus.objectFields match {
case Some("x" :: _) => implicitly[DecodeJson[Foo]].decode(c)
case _ => implicitly[DecodeJson[Bar]].decode(c)
})
但是,失敗因爲argonaut.DecodeResult
是不變的。
<console>:42: error: type mismatch;
found : argonaut.DecodeResult[Foo]
required: argonaut.DecodeResult[Parent]
Note: Foo <: Parent, but class DecodeResult is invariant in type A.
You may wish to define A as +A instead. (SLS 4.5)
case Some("x" :: _) => implicitly[DecodeJson[Foo]].decode(c)
^
<console>:43: error: type mismatch;
found : argonaut.DecodeResult[Bar]
required: argonaut.DecodeResult[Parent]
Note: Bar <: Parent, but class DecodeResult is invariant in type A.
You may wish to define A as +A instead. (SLS 4.5)
case _ => implicitly[DecodeJson[Bar]].decode(c)
^
所以,後來我想出了:
implicit val parentDecodeJson: DecodeJson[Parent] =
DecodeJson(c => c.focus.objectFields match {
case Some("x" :: _) => implicitly[DecodeJson[Foo]].decode(c).flatMap{a => DecodeResult.ok(a)}
case _ => implicitly[DecodeJson[Bar]].decode(c).flatMap{a => DecodeResult.ok(a)}
})
,似乎工作:
scala> Json.obj(("x", jNumber(42))).as[Parent]
res2: argonaut.DecodeResult[Parent] = DecodeResult(Right(Foo(42)))
scala> Json.obj(("y", jString("hi!"))).as[Parent]
res3: argonaut.DecodeResult[Parent] = DecodeResult(Right(Bar(hi!)))
有一個更清潔的方式?
這應該是開箱即用的, 至少從README說的是什麼(https://github.com/alexarchambault/argonaut-shapeless) –
這個怎麼樣:https://stackoverflow.com/questions/39108841 /解碼-A-密封特質在-淘金者基於上JSON結構 – tkachuko