首页 > 解决方案 > 在 circe 中解码 case 类、String 或 Int

问题描述

我使用一些带有 json 响应的 Rest API,其中包含一种“混合”字段。混合是指它可以采用不同类型的值。在我的情况下ObjectString并且Int是允许的。Object本身由 1和Int1组成String

我需要解码的对象如下所示:

{
   field1: 32,
   ...
   value: {
      id: 23,
      text: "text"
   }
}

{
   field1: 32,
   ...
   value: 21
}

{
   field1: 32,
   ...
   value: "value"
}

如何处理circe中的此类对象?

标签: jsonscalacirce

解决方案


假设您的案例类是:

@JsonCodec(decodeOnly = true)
case class X(id: Int, text: String)

然后我可以假设您的字段类型为:

type Mixed = X Either Int Either String

解码可能如下所示:

implicit val mixedDecoder: Decoder[Mixed] = 
  Decoder[X].map[Mixed](x => Left(Left(x))) or Decoder[Int].map[Mixed](i => Left(Right(i))) or Decoder[String].map[Mixed](s => Right(s))

如果您定义它们的组合方式,您可以派生编解码器Either:左胜、右胜或任何您喜欢的:

implicit def eitherDecode[L: Decoder, R: Decoder]: Decoder[L Either R] =
  Decoder[L].map[L Either R](Left(_)) or Decoder[R].map[L Either R](Right(_))

或者,您可以创建自己的 ADT(密封特征 + 案例类),然后编写手写解码器以避免使用鉴别器字段。

底线是你必须以某种方式表达你正在解码的类型的多态性(以一种理智的方式 -Any不算数),然后提供一个解码器来解码它。然后你可以简单地使用它:

@JsonCodec(decodeOnly = true)
case class BigClass(field1: String, value: Mixed)

推荐阅读