Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在scala中使用选项[A,B]]解析json的替代方法_Json_Scala_Abstract Data Type_Circe - Fatal编程技术网

在scala中使用选项[A,B]]解析json的替代方法

在scala中使用选项[A,B]]解析json的替代方法,json,scala,abstract-data-type,circe,Json,Scala,Abstract Data Type,Circe,例如,此处的有效负载是可选的,它有3种变体: 我如何使用option[A,B,C]]等类型解析json,而使用sealed-trait或sum-type来使用抽象数据类型 以下是一些锅炉板的最小示例: 您的代码几乎没有问题,您的json和记录中只有语法问题。id应该是Double,而不是Int——因为这就是json中该字段的显示方式(“id”:2.1)。请在下面查找固定版本: val json = s"""[ { "id": 1,

例如,此处的
有效负载是可选的,它有3种变体:

我如何使用option[A,B,C]]等类型解析json,而使用sealed-trait或sum-type来使用抽象数据类型

以下是一些锅炉板的最小示例:


您的代码几乎没有问题,您的json和
记录中只有语法问题。id
应该是
Double
,而不是
Int
——因为这就是json中该字段的显示方式(
“id”:2.1
)。请在下面查找固定版本:

val json =
      s"""[
       {
         "id": 1,
         "payload" : "data"
       },
       {
         "id": 2.1,
         "payload" : {
           "field1" : "field1",
           "field2" : 5,
           "field3" : true
         }
       },
       {
         "id": 2.2,
         "payload" : {
           "field1" : "field1"
         }
       },    





       {
         "id": 3,
         "payload" : 4
       },





       {
         "id": 4
       }
     ]"""

    type Payload = Either[String, Data]
    final case class Data(field1: String, field2: Option[Int])
    final case class Record(id: Double, payload: Option[Payload]) // id is a Double in your json in some cases

    import io.circe.Decoder
    import io.circe.generic.semiauto.deriveDecoder

    implicit val dataDecoder: Decoder[Data] = deriveDecoder
    implicit val payloadDecoder: Decoder[Payload] = Decoder[String] either Decoder[Data]
    implicit val recordDecoder: Decoder[Record] = deriveDecoder

    val result = io.circe.parser.decode[List[Record]](json)
    println(result)
在我的案例中产生了:

Right(List(Record(1.0,Some(Left(data))), Record(2.1,Some(Right(Data(field1,Some(5))))), Record(2.2,Some(Right(Data(field1,None)))), Record(3.0,Some(Left(4))), Record(4.0,None)))
更新:

更通用的方法是使用所谓的
Sum类型
,或者简单地说-general
sealed trait
,使用几种不同的实现。有关更多详细信息,请参见下一个Circe文档页面:

在您的情况下,可以通过以下方式实现:

import cats.syntax.functor._
  import io.circe.Decoder
  import io.circe.generic.semiauto.deriveDecoder

  sealed trait Payload

  object Payload {
    implicit val decoder: Decoder[Payload] = {
      List[Decoder[Payload]](
        Decoder[StringPayload].widen,
        Decoder[IntPayload].widen,
        Decoder[ObjectPayload].widen
      ).reduce(_ or _)
    }
  }

  case class StringPayload(value: String) extends Payload

  object StringPayload {
    implicit val decoder: Decoder[StringPayload] = Decoder[String].map(StringPayload.apply)
  }

  case class IntPayload(value: Int) extends Payload

  object IntPayload {
    implicit val decoder: Decoder[IntPayload] = Decoder[Int].map(IntPayload.apply)
  }

  case class ObjectPayload(field1: String, field2: Option[Int]) extends Payload

  object ObjectPayload {
    implicit val decoder: Decoder[ObjectPayload] = deriveDecoder
  }

  final case class Record(id: Double, payload: Option[Payload])

  object Record {
    implicit val decoder: Decoder[Record] = deriveDecoder
  }

  def main(args: Array[String]): Unit = {
    val json =
      s"""[
       {
         "id": 1,
         "payload" : "data"
       },
       {
         "id": 2.1,
         "payload" : {
           "field1" : "field1",
           "field2" : 5,
           "field3" : true
         }
       },
       {
         "id": 2.2,
         "payload" : {
           "field1" : "field1"
         }
       },
       {
         "id": 3,
         "payload" : "4"
       },
       {
         "id": 4
       }
     ]"""

    val result = io.circe.parser.decode[List[Record]](json)
    println(result)
  }
在我的案例中产生了下一个输出:

Right(List(Record(1.0,Some(StringPayload(data))), Record(2.1,Some(ObjectPayload(field1,Some(5)))), Record(2.2,Some(ObjectPayload(field1,None))), Record(3.0,Some(StringPayload(4))), Record(4.0,None)))

希望这有帮助

我们可以选择不将payload=4转换为字符串类型吗?这里的目标是分析有效负载、字符串、int和对象类型的3种类型。@cpchung是的,你是对的,请原谅我在开始时发布了非sens答案,我刚刚更新了它。请看一看。非常感谢。
Right(List(Record(1.0,Some(StringPayload(data))), Record(2.1,Some(ObjectPayload(field1,Some(5)))), Record(2.2,Some(ObjectPayload(field1,None))), Record(3.0,Some(StringPayload(4))), Record(4.0,None)))