【问题标题】:Decode case class, String or Int in circe在circe中解码case类,String或Int
【发布时间】:2020-09-17 23:28:27
【问题描述】:

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

我需要解码的对象如下:

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

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

III

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

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

【问题讨论】:

    标签: json scala circe


    【解决方案1】:

    假设您的案例类是:

    @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)
    

    【讨论】:

      【解决方案2】:

      @SomeName 创建的方法类似,但解码器不需要HCursor

      sealed trait Value
      object Value {
        final case class Values(id: Int, text: String) extends Value
        final case class IntValue(i: Int) extends Value
        final case class StringValue(s: String) extends Value
      
        implicit val valueDecoder: Decoder[Value] = Decoder[String]
          .map[Value](StringValue)
          .or(Decoder[Int].map[Value](IntValue))
          .or(Decoder.forProduct2("id", "text")(Values.apply).map[Value](identity))
      }
      

      以及封闭对象:

      final case class Example(field1: Int, value: Value)
      object Example {
        implicit val exampDecoder: Decoder[Example] =
          Decoder.forProduct2("field1", "value")(Example.apply)
      }
      

      运行它:

      import io.circe.Decoder
      import io.circe.parser._
      
      def main(args: Array[String]): Unit = {
        val fst =
          """
            |{
            |   "field1": 32,
            |   "value": {
            |      "id": 23,
            |      "text": "text"
            |   }
            |}""".stripMargin
      
        val snd =
          """
            |{
            |   "field1": 32,
            |   "value": 21
            |}
            |""".stripMargin
      
        val third =
          """{
            |   "field1": 32,
            |   "value": "value"
            |}
            |""".stripMargin
      
        println(decode[Example](fst))
        println(decode[Example](snd))
        println(decode[Example](third))
      }
      

      结果:

      Right(Example(32,Values(23,text)))
      Right(Example(32,IntValue(21)))
      Right(Example(32,StringValue(value)))
      

      【讨论】:

        【解决方案3】:

        在查看@MateuszKubuszok 提供的答案之前,我最终编写了一个自定义解码器。为了完整起见,我会把它放在这里。

        sealed trait SomeValue
        final case class SomeObjValue(id: Int, text: String) extends SomeValue
        final case class SomeIntValue(int: Int) extends SomeValue
        final case class SomeStringValue(str: String) extends SomeValue
        
        implicit def someValueDecode: Decoder[SomeValue] =
          (cursor: HCursor) =>
            if (cursor.value.isObject) Decoder[SomeObjValue].apply(cursor)
            else if (cursor.value.isString) cursor.value.as[String].map(SomeStringValue)
            else if (cursor.value.isNumber) cursor.value.as[Int].map(SomeIntValue)
            else
              Decoder.resultInstance.raiseError(
              DecodingFailure(s"${cursor.value} is not supported for decoding", List())
            )
        

        【讨论】:

          猜你喜欢
          • 2019-03-15
          • 2019-03-15
          • 2021-09-21
          • 2020-10-28
          • 2019-05-31
          • 2020-07-06
          • 2017-11-27
          • 2018-12-24
          • 2019-03-13
          相关资源
          最近更新 更多