我正在尝试解析 json 像
{
"element": "string",
"content": "application/json"
}
其中element
决定 JSON 的类型。但是我的代码无法解析。
http://scastie.org/15213
import scalaz._, Scalaz._
import argonaut._, Argonaut._, Shapeless._
case class ArrayAttributes(default: List[StringElement])
sealed trait Element
case class StringElement(content: String) extends Element
case class ArrayElement(attributes: ArrayAttributes, content: List[Element]) extends Element
case class Reference(element: String) extends Element { def content = element }
object Parser {
def kindDecode[T](
kinds: Map[String, DecodeJson[T]],
fail: HCursor => DecodeResult[T] = { c: HCursor => DecodeResult.fail[T]("expected one of ${kind.keys}", c.history) }): DecodeJson[T] = DecodeJson(c =>
(c -- "element").as[String].flatMap { kind =>
kinds.get(kind).map(_.decode(c)).getOrElse(fail(c))
}
)
implicit def elementDecode: DecodeJson[Element] = kindDecode(
Map(
"string" -> DecodeJson.of[StringElement].map(identity[Element]),
"array" -> arrayDecode.map(identity[Element])
),
{ c => DecodeJson.of[Reference].decode(c).map(identity[Element]) }
)
def arrayDecode: DecodeJson[ArrayElement] = jdecode2L(ArrayElement.apply)("attributes", "content")
}
我将用阿尔戈英雄无形(1.0.0-M1
)的当前里程碑来回答,自0.3.1
版本以来,它已经增加了相关内容。
它允许为总和类型指定所谓的JsonSumCodec
,这些类型驱动子类型的编码/区分方式。
通过在其伴随对象中为Element
定义一个,例如
implicit val jsonSumCodecForElement = derive.JsonSumCodecFor[Element](
derive.JsonSumTypeFieldCodec(
typeField = "element",
toTypeValue = Some(_.stripSuffix("Element").toLowerCase)
)
)
您的示例有效:
> Parse.decodeEither[Element](member)
res1: (String / (String, CursorHistory)) / Element =
/-(StringElement(application/json))
上面JsonSumCodecFor
是一个类型类,它为给定类型提供JsonSumCodec
,此处Element
。作为JsonSumCodec
,我们选择 JsonSumTypeFieldCodec
,它使用字段(默认情况下"type"
)来区分子类型。在这里,我们选择 "element"
而不是 "type"
,并且我们还转换子类型名称(toTypeValue
参数),以便它们与示例输入的名称匹配。