首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Argonaut:解码多态数组

Argonaut:解码多态数组
EN

Stack Overflow用户
提问于 2016-11-22 20:47:40
回答 1查看 413关注 0票数 3

我试图为其编写DecodeJson[T]的JSON对象包含一个不同“类型”的数组(意味着其元素的JSON结构是可变的)。唯一常见的特性是type字段,它可以用来区分类型。其他所有的领域都不同。示例:

代码语言:javascript
复制
{
    ...,
    array: [
        { type: "a", a1: ..., a2: ...},
        { type: "b", b1: ...},
        { type: "c", c1: ..., c2: ..., c3: ...},
        { type: "a", a1: ..., a2: ...},
        ...
    ],
    ...
}

使用argonaut,是否可以将JSON数组映射到Scala Seq[Element],其中ElementElementAElementB等类型的合适案例类的超级类型?

我对play-json也做了同样的事情,它非常容易(基本上是一个评估type字段并相应地转发到更具体的ReadsReads[Element] )。但是,我想不出用argonaut做这个的方法。

编辑:示例

Scala类型(我希望使用):

代码语言:javascript
复制
case class Container(id: Int, events: List[Event])

sealed trait Event
case class Birthday(name: String, age: Int) extends Event
case class Appointment(start: Long, participants: List[String]) extends Event
case class ... extends Event

JSON实例(不在我的控制范围内):

代码语言:javascript
复制
{
   "id":1674,
   "events": {
      "data": [
         {
            "type": "birthday",
            "name": "Jones Clinton",
            "age": 34
         },
         {
            "type": "appointment",
            "start": 1675156665555,
            "participants": [
               "John Doe",
               "Jane Doe",
               "Foo Bar"
            ]
         }
      ]
   }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-11-22 23:09:32

您可以创建一个小函数来帮助您构建一个处理此格式的解码器。

下面是一个例子。

代码语言:javascript
复制
import argonaut._, Argonaut._

def decodeByType[T](encoders: (String, DecodeJson[_ <: T])*) = {
  val encMap = encoders.toMap

  def decoder(h: CursorHistory, s: String) =
    encMap.get(s).fold(DecodeResult.fail[DecodeJson[_ <: T]](s"Unknown type: $s", h))(d => DecodeResult.ok(d))

  DecodeJson[T] { c: HCursor =>
    val tf = c.downField("type")

    for {
      tv   <- tf.as[String]
      dec  <- decoder(tf.history, tv)
      data <- dec(c).map[T](identity)
    } yield data
  }
}

case class Container(id: Int, events: ContainerData)
case class ContainerData(data: List[Event])

sealed trait Event
case class Birthday(name: String, age: Int) extends Event
case class Appointment(start: Long, participants: List[String]) extends Event

implicit val eventDecoder: DecodeJson[Event] = decodeByType[Event](
  "birthday" -> DecodeJson.derive[Birthday],
  "appointment" -> DecodeJson.derive[Appointment]
)

implicit val containerDataDecoder: DecodeJson[ContainerData] = DecodeJson.derive[ContainerData]
implicit val containerDecoder: DecodeJson[Container] = DecodeJson.derive[Container]

val goodJsonStr =
  """
    {
       "id":1674,
       "events": {
          "data": [
             {
                "type": "birthday",
                "name": "Jones Clinton",
                "age": 34
             },
             {
                "type": "appointment",
                "start": 1675156665555,
                "participants": [
                   "John Doe",
                   "Jane Doe",
                   "Foo Bar"
                ]
             }
          ]
       }
    }
  """

def main(args: Array[String]) = {
  println(goodJsonStr.decode[Container])

  // \/-(Container(1674,ContainerData(List(Birthday(Jones Clinton,34), Appointment(1675156665555,List(John Doe, Jane Doe, Foo Bar))))))
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40751321

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档