Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/19.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
解码json字符串中的json_Json_Scala_Circe - Fatal编程技术网

解码json字符串中的json

解码json字符串中的json,json,scala,circe,Json,Scala,Circe,我处理的是一个JSON对象,其中一个值(blob)是字符串化的JSON对象: { "credential": { "blob": "{\"access\":\"181920\",\"secret\":\"secretKey\"}", "project_id": "731fc6f265cd486d900f16e84c5cb594", "type": "ec2", "user_id": "bb5476fd12884539b41d

我处理的是一个JSON对象,其中一个值(blob)是字符串化的JSON对象:

{
    "credential": {
        "blob": "{\"access\":\"181920\",\"secret\":\"secretKey\"}",
        "project_id": "731fc6f265cd486d900f16e84c5cb594",
        "type": "ec2",
        "user_id": "bb5476fd12884539b41d5a88f838d773"
    }
}
我的域类是:

case class Credential(access: String, secret: String, projectId: String, userId: String)
对域类进行编码很容易:

implicit val encoder: Encoder[Credential] = (a: Credential) => Json.obj(
  "type" -> "ec2".asJson,
  "blob" -> Map("access" -> a.access, "secret" -> a.secret).asJson.noSpaces.asJson,
  "project_id" -> a.projectId.asJson,
  "user_id" -> a.userId.asJson
)
但是解码要困难得多:

implicit val decoder: Decoder[Credential] = (c: HCursor) => for {
  blobJsonString <- c.get[String]("blob")
  blob <- decode[Json](blobJsonString).left.map(e => DecodingFailure(e.getMessage, c.downField("blob").history))
  access <- blob.hcursor.get[String]("access")
  secret <- blob.hcursor.get[String]("secret")
  projectId <- c.get[String]("project_id")
  userId <- c.get[String]("user_id")
} yield Credential(access, secret, projectId, userId)
隐式val解码器:解码器[凭证]=(c:HCursor)=>用于{

blobJsonString好吧,因为所描述的JSON并不是真正的典型情况,我不确定是否可以完全避免手动解析,但是如果您要更改表示此结构的case类,您可以利用circe提供的一些优势。 请查找下面的代码示例:

import io.circe._
import io.circe.generic.semiauto._
import io.circe.generic.auto._

object CredentialsParseApp {
  case class CredentialsBlob(access: String, secret: String)

  object CredentialsBlob {

    implicit val encoder: Encoder[CredentialsBlob] = {
      val derivedEncoder: Encoder[CredentialsBlob] = deriveEncoder[CredentialsBlob]
      Encoder[String].contramap(blob => derivedEncoder(blob).noSpaces)
    }

    implicit val decoder: Decoder[CredentialsBlob] = {
      val derivedDecoder: Decoder[CredentialsBlob] = deriveDecoder[CredentialsBlob]
      Decoder[String].emap { value =>
        for {
          json <- parser.parse(value).left.map(_.message)
          blob <- json.as(derivedDecoder).left.map(_.message)
        } yield blob
      }
    }
  }

  case class Credentials(blob: CredentialsBlob, project_id: String, `type`: String = "ec2", user_id: String)
  case class Response(credential: Credentials)

  def main(args: Array[String]): Unit = {
    val jsonString =
      """{
         |    "credential": {
         |        "blob": "{\"access\": \"181920\", \"secret\": \"secretKey\" }",
         |        "project_id": "731fc6f265cd486d900f16e84c5cb594",
         |        "type": "ec2",
         |        "user_id": "bb5476fd12884539b41d5a88f838d773"
         |    }
         |}""".stripMargin

    println(parser.parse(jsonString).flatMap(_.as[Response]))
  }
}

我使用了circe版本“0.12.3”对于这个例子。希望这有帮助!

这是一个很好的改进,但基本问题仍然是一样的。@SimãoMartins是的,我同意这仍然需要手工工作才能将这个字符串解析为有意义的结构,但从我的观点来看,这并不是一个真正的问题,因为这是一个角盒,对于它来说,
解码器
基础结构这是真的。另一个选择是更改JSON模式,但恐怕这是外部API,不在您的控制之下。您是说仅使用解码器是不可能的?或者换句话说,不使用解析器模块是不可能的?@SimãoMartins恐怕是这样的,因为这是一种特殊情况,开箱即用的lib不支持。但是,我不这么认为这确实是一个问题,因为如果您认为ussual JSON不应该在字段中以字符串的形式出现,那么JSON解析库通常不支持这种情况,而是将处理这种情况的工具,就像circe中的自定义编解码器一样。为了证明这一点,我将指向circe文档中的
Instant
示例-如果您发布一个回答说它的imp如果不使用解析器模块,我会将其标记为已接受/正确(我记不起术语)
Right(Response(Credentials(CredentialsBlob(181920,secretKey),731fc6f265cd486d900f16e84c5cb594,ec2,bb5476fd12884539b41d5a88f838d773)))