解码json字符串中的json
我处理的是一个JSON对象,其中一个值(blob)是字符串化的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
{
"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)))