我正在使用 Argonaut 解析来自远程 JSON 提供程序的对象。API 有两种类型的端点,一种是 URL 上的传统 REST 请求和单个 JSON 对象的响应。我能够在这种类型的端点上使用 Argonaut 轻松解析复杂的 JSON 返回对象。
我的问题是提供者的流端点,它从给定端点的一组有界 JSON 中返回随机 JSON 对象。这些对象按照它们在站点上出现的顺序返回,并且可以随时返回大约 20 个不同对象中的任何一个。
通过 API 工作,我找不到使用 Argonaut 处理此问题的方法。API 似乎都需要类型参数化,这在无法预测下一个对象的类型的环境中是很困难的。一种选择是根据每个 JSON 块中的前几个字符分派到不同的编解码器,但这会破坏将 JSON 字符串发送到解析器并获得对象作为回报的目标。
到目前为止,我能找到的最好的方法是让所有顶级案例类扩展一个空trait
:
implicit def ModelDecodeJson: DecodeJson[Model] =
DecodeJson(c =>
c.as[ModelSubclassA].asInstanceOf[DecodeResult[Model]]
||| c.as[ModelSubclassB].asInstanceOf[DecodeResult[Model]]
// many more here!
)
不幸的是,ModelSubclassA
两者ModelSubclassB
都与其他案例类有几个关联,虽然这个示例可以编译,但在尝试解析这些子类型时它会在运行时失败。总之,将有几十个案例类构成返回数据的层次结构。
我也尝试过用for
理解来构建它,但也没有运气。
谁能在这里建议更好的模式?
更新
以下似乎具有更具可扩展性的模式,但类型不合作:
implicit def ModelDecodeJson: DecodeJson[Model] =
DecodeJson(c =>
(c.as[ModelSubclassA] ||| c.as[ModelSubclassB]).asInstanceOf[DecodeResult[Model]]
)
错误:(10, 17) 类型不匹配;找到:argonaut.DecodeResult[ModelSubclassB] 需要:argonaut.DecodeResult[Product with Serializable with Model] 注意:ModelSubclassB <: Product with Serializable with Model,但类 DecodeResult 在类型 A 中是不变的。您可能希望将 A 定义为 +A . (SLS 4.5) ||| c.as[ModelSubclassB]).asInstanceOf[DecodeResult[Model]] ^
所以我开始查看源代码,并意识到6.2-M1 版本中的错误所暗示的定义DecodeResult
已更改为包含。+A
不幸的是,升级到该版本将所有Model
子类编解码器都变成了模棱两可的隐式,这是有道理的。
啊...