ZIO Json:反序列化含密封特质的Tickers结构时Fiber失败,提示预期'{'却得到'['
解决Scala JSON反序列化中的结构不匹配与密封特质解码问题
一、先解决当前的直接错误:JSON结构不匹配
你遇到的Assertion failed: Fiber failed. A checked error was not handled. .data(expected '{' got '[')错误,本质是JSON输入结构和你定义的Tickers类不匹配:
Tickers是包含data: Seq[CexPair]的case class,对应的JSON应该是一个外层对象,示例格式如下:{ "data": [ {"timestamp": "2024-01-01", "bid": 1.23, "ask": 1.24}, {"timestamp": "2024-01-02"} ] }- 但你的实际输入大概率是直接的JSON数组(没有外层
data对象包裹),比如:[ {"timestamp": "2024-01-01", "bid": 1.23, "ask": 1.24}, {"timestamp": "2024-01-02"} ]
针对这个问题,你可以根据实际输入选择两种修正方向:
- 如果输入确实是带
data字段的对象:- 检查输入JSON是否符合外层对象格式,确保没有语法错误(比如遗漏外层
{})。
- 检查输入JSON是否符合外层对象格式,确保没有语法错误(比如遗漏外层
- 如果输入就是直接的数组:
- 你当前定义的
decoderPairs基于decoderTickers映射data字段,会先尝试把输入解析成Tickers对象,自然会因输入是数组报错。你需要直接定义数组解码器:implicit val decoderPairs: JsonDecoder[Seq[CexPair]] = JsonDecoder.seq(decoderCexPair)
- 你当前定义的
二、密封特质CexPair的反序列化注意事项(潜在问题)
虽然当前错误不是密封特质导致的,但如果不处理好子类区分逻辑,后续反序列化CexPair子类时会出现异常:
自动生成的DeriveJsonDecoder.gen对于密封特质的子类,需要明确标识来判断实例化哪个子类。你可以通过两种方式解决:
1. 使用鉴别器字段(推荐)
以zio-json为例,可以给密封特质的解码器添加一个鉴别器字段(比如type),让JSON里的每个对象都带上子类标识:
implicit val decoderCexPair: JsonDecoder[CexPair] = DeriveJsonDecoder.gen[CexPair].withDiscriminator("type")
对应的JSON对象需要包含子类标识:
{"type": "CexPairWithBidAsk", "timestamp": "2024-01-01", "bid": 1.23, "ask": 1.24}
或
{"type": "CexPairWithoutBidAsk", "timestamp": "2024-01-02"}
2. 手动编写解码器(基于字段存在性判断)
如果你的JSON里没有鉴别器字段,可以通过检查特定字段(比如bid/ask)是否存在来区分子类:
implicit val decoderCexPair: JsonDecoder[CexPair] = JsonDecoder.instance { cursor => // 尝试获取bid字段,失败则判定为无bid/ask的子类 cursor.get[Double]("bid").fold( _ => cursor.as[CexPairWithoutBidAsk], _ => cursor.as[CexPairWithBidAsk] ) }
总结
- 先确认JSON输入结构,修正解码器与输入的匹配问题,解决当前的
expected '{' got '['错误; - 完善密封特质
CexPair的解码器逻辑,确保能正确区分两个子类。
内容的提问来源于stack exchange,提问作者Aarkon
相关产品推荐
相关产品推荐

