使用 Argonaut 解析 JSON 的流

Parsing stream of JSON with Argonaut

我正在使用 Argonaut 解析来自远程 JSON 提供程序的对象。 API 有两种端点,一种是 URL 处的传统 REST 请求,另一种是单个 JSON 对象的响应。我能够在这种类型的端点上使用 Argonaut 轻松解析复杂的 JSON return 对象。

我的问题出在提供者的流端点上,它 return 从给定端点的有界集合 JSON 中随机 JSON 对象。这些对象按照它们在网站上出现的顺序 return 编辑,大约二十个不同对象中的任何一个都可以随时 return 编辑。

经过 APIs,我找不到使用 Argonaut 来处理这个问题的方法。 API 似乎都需要类型参数化,这在无法预测下一个对象类型的环境中是很困难的。一种选择是根据 JSON 每个块中的前几个字符分派到不同的编解码器,但这破坏了将 JSON 字符串发送到解析器并在 return 中获取对象的目标].

到目前为止我能找到的最好的方法是让所有顶级案例 类 扩展一个空的 trait:

implicit def ModelDecodeJson: DecodeJson[Model] =
  DecodeJson(c =>
    c.as[ModelSubclassA].asInstanceOf[DecodeResult[Model]]
      ||| c.as[ModelSubclassB].asInstanceOf[DecodeResult[Model]]
      // many more here!
  )

不幸的是,ModelSubclassAModelSubclassB 都与其他情况 类 有多个关联,并且在编译此示例时,当尝试解析这些子类型时,它会在运行时失败。总共将有几十个案例 类 构成 returned 数据的层次结构。

我也尝试过用 for 理解来构建它,但也没有成功。

谁能在这里建议更好的模式?

更新

以下似乎具有更具可扩展性的模式,但类型不合作:

implicit def ModelDecodeJson: DecodeJson[Model] =
  DecodeJson(c =>
    (c.as[ModelSubclassA] ||| c.as[ModelSubclassB]).asInstanceOf[DecodeResult[Model]]
  )

Error:(10, 17) type mismatch; found : argonaut.DecodeResult[ModelSubclassB] required: argonaut.DecodeResult[Product with Serializable with Model] Note: ModelSubclassB <: Product with Serializable with Model, but class DecodeResult is invariant in type A. You may wish to define A as +A instead. (SLS 4.5) ||| c.as[ModelSubclassB]).asInstanceOf[DecodeResult[Model]] ^

所以我开始查看源代码并意识到 DecodeResult 的定义已更改为包含 +A,如版本 6.2-M1 中的错误所建议的那样。不幸的是,升级到该版本后,所有 Model 子类编解码器都变成了不明确的隐式,这是有道理的。

呃...

这个问题的答案需要两篇:

  1. "Sum Types" 封装值并使编解码器与用于 return 值的类型保持距离。在上面的示例中,编解码器使用 Model 特性来解析隐式。如果它也用作 return 类型,则会引入编译器无法明确解析的递归定义。

  2. 一旦使用了总和类型,客户端就很容易接受这些类型并在 match 中使用提取器来获取其中的实际值。