无法使用 Circe JSON 解析器创建遍历 JSON 字符串的对象
Cannot created object walking though JSON string using Circe JSON parser
所以我正在尝试为要转换为域对象的 JSON 字符串创建自定义解码器。
我正在使用 Scala/Circe 遍历 JSON 并创建对象。
我无法将此发送到 运行。我确定我不清楚如何走过 JSON。有人可以建议吗?
这是有问题的JSON,
{
"args": {},
"headers": {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "en-US,en;q=0.9",
"Host": "httpbin.org",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36"
},
"origin": "61.16.136.118, 61.16.136.118",
"url": "https://httpbin.org/get"
}
这是我的代码,
import com.softwaremill.sttp._
import com.softwaremill.sttp.circe._
import io.circe._, io.circe.parser._
case class Headers(Accept: String, Accept_Encoding: String, Accept_Language: String, Host: String, Upgrade_Insecure_Requests: String, User_Agent: String)
case class RootInterface(args: String, headers: Headers, origin: String, url: String)
object SttpClientGetPost extends App {
implicit val backend = HttpURLConnectionBackend()
implicit val rootDecoder: Decoder[RootInterface] =
(hCursor: HCursor) => {
val tcursor = hCursor.downField("headers")
val argsCursor = hCursor.downField("args")
for{
args <- for{
testString <- argsCursor.get[String]("args")
}yield testString
headers <- for {
Accept <- tcursor.downField("Accept").as[String]
Accept_Encoding <- tcursor.downField("Accept-Encoding").as[String]
Accept_Language <- tcursor.downField("Accept-Language").as[String]
Host <- tcursor.downField("Host").as[String]
Upgrade_Insecure_Requests <- tcursor.downField("Upgrade-Insecure-Requests").as[String]
User_Agent <- tcursor.downField("User-Agent").as[String]
} yield Headers(Accept, Accept_Encoding, Accept_Language, Host, Upgrade_Insecure_Requests, User_Agent)
origin <- hCursor.downField("Origin").as[String]
url <- hCursor.downField("url").as[String]
} yield RootInterface("", headers, origin, url)
}
val secondRequest = sttp //.headers(("userId", USER_ID),("password","testpassword"))
.get(uri"http://httpbin.org/get")
secondRequest.send().body match {
case Left(fail) => System.out.println("The Get request was unsuccessful. " + fail)
case Right(rawJSONResponse) =>
parser.decode(rawJSONResponse) match {
case Left(fail) => System.out.println("The JSON response could not be parsed by Circe. " + fail)
case Right(rootInterfaceObject) =>
System.out.println("Origin :" + rootInterfaceObject.origin)
}
}
}
更新:
我现在正在尝试这个无济于事,
case class Headers(Accept: String, Accept_Encoding: String, Accept_Language: String, Host: String, Upgrade_Insecure_Requests: String, User_Agent: String)
case class RootInterface(args: String, headers: Headers, origin: String, url: String)
val doc = """{
"args": {},
"headers": {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "en-US,en;q=0.9",
"Host": "httpbin.org",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36"
},
"origin": "61.16.136.118, 61.16.136.118",
"url": "https://httpbin.org/get"
}"""
implicit val decodeHeaders: Decoder[Headers] = Decoder.forProduct6(
"Accept",
"Accept-Encoding",
"Accept-Language",
"Host",
"Upgrade-Insecure-Requests",
"User-Agent"
)(Headers(_, _, _, _, _, _))
implicit val decodeRootInterface: Decoder[RootInterface] = Decoder.forProduct4(
"args",
"headers",
"origin",
"url"
)(RootInterface(_, _, _, _))
val t = decode[RootInterface](doc)
我仍然遇到解码失败的问题。它看起来像是因为 args
字段。
我强烈建议您组合地构建您的实例——例如您可以定义一个单独的 Decoder[Headers]
实例,然后在您的 Decoder[RootInterface]
中使用它,而不是将所有 Headers
解码逻辑烘焙到 RootInterface
解码器中。
我还建议避免直接使用游标,除非您正在做一些您知道需要那种定义级别的特别复杂的事情。
所以给定这份文件:
val doc = """{
"args": {},
"headers": {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "en-US,en;q=0.9",
"Host": "httpbin.org",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36"
},
"origin": "61.16.136.118, 61.16.136.118",
"url": "https://httpbin.org/get"
}"""
…这些案例 classes:
case class Headers(Accept: String, Accept_Encoding: String, Accept_Language: String, Host: String, Upgrade_Insecure_Requests: String, User_Agent: String)
case class RootInterface(args: String, headers: Headers, origin: String, url: String)
…以下是您可以在 REPL 中使用的完整工作示例:
import io.circe.Decoder, io.circe.jawn.decode
implicit val decodeHeaders: Decoder[Headers] = Decoder.forProduct6(
"Accept",
"Accept-Encoding",
"Accept-Language",
"Host",
"Upgrade-Insecure-Requests",
"User-Agent"
)(Headers(_, _, _, _, _, _))
implicit val decodeRootInterface: Decoder[RootInterface] = Decoder.forProduct3(
"headers",
"origin",
"url"
)(RootInterface("", _, _, _))
……像这样:
scala> decode[RootInterface](doc)
res0: Either[io.circe.Error,RootInterface] = Right(RootInterface(,Headers(text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3,gzip, deflate,en-US,en;q=0.9,httpbin.org,1,Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36),61.16.136.118, 61.16.136.118,https://httpbin.org/get))
(我不确定 args
解码的目的是什么,所以我只是按照您使用空字符串的实现。)
不过,如果您控制 Headers
大小写 class 定义,我强烈建议您使用惯用的 Scala 成员名称(即驼峰式,而不是 upper snake)。在我看来,将其与 circe-derivation 相结合是一个非常明确的解决方案:
import io.circe.Decoder, io.circe.derivation.deriveDecoder
case class Headers(
accept: String,
acceptEncoding: String,
acceptLanguage: String,
host: String,
upgradeInsecureRequests: String,
userAgent: String
)
object Headers {
implicit val decodeHeaders: Decoder[Headers] = deriveDecoder(
_.replaceAll("([A-Z])", "-").capitalize
)
}
case class RootInterface(
args: Map[String, String],
headers: Headers,
origin: String,
url: String
)
object RootInterface {
implicit val decodeRootInterface: Decoder[RootInterface] = deriveDecoder
}
然后:
scala> io.circe.jawn.decode[RootInterface](doc)
res0: Either[io.circe.Error,RootInterface] = Right(RootInterface(Map(),Headers(text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3,gzip, deflate,en-US,en;q=0.9,httpbin.org,1,Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36),61.16.136.118, 61.16.136.118,https://httpbin.org/get))
所以我正在尝试为要转换为域对象的 JSON 字符串创建自定义解码器。 我正在使用 Scala/Circe 遍历 JSON 并创建对象。 我无法将此发送到 运行。我确定我不清楚如何走过 JSON。有人可以建议吗?
这是有问题的JSON,
{
"args": {},
"headers": {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "en-US,en;q=0.9",
"Host": "httpbin.org",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36"
},
"origin": "61.16.136.118, 61.16.136.118",
"url": "https://httpbin.org/get"
}
这是我的代码,
import com.softwaremill.sttp._
import com.softwaremill.sttp.circe._
import io.circe._, io.circe.parser._
case class Headers(Accept: String, Accept_Encoding: String, Accept_Language: String, Host: String, Upgrade_Insecure_Requests: String, User_Agent: String)
case class RootInterface(args: String, headers: Headers, origin: String, url: String)
object SttpClientGetPost extends App {
implicit val backend = HttpURLConnectionBackend()
implicit val rootDecoder: Decoder[RootInterface] =
(hCursor: HCursor) => {
val tcursor = hCursor.downField("headers")
val argsCursor = hCursor.downField("args")
for{
args <- for{
testString <- argsCursor.get[String]("args")
}yield testString
headers <- for {
Accept <- tcursor.downField("Accept").as[String]
Accept_Encoding <- tcursor.downField("Accept-Encoding").as[String]
Accept_Language <- tcursor.downField("Accept-Language").as[String]
Host <- tcursor.downField("Host").as[String]
Upgrade_Insecure_Requests <- tcursor.downField("Upgrade-Insecure-Requests").as[String]
User_Agent <- tcursor.downField("User-Agent").as[String]
} yield Headers(Accept, Accept_Encoding, Accept_Language, Host, Upgrade_Insecure_Requests, User_Agent)
origin <- hCursor.downField("Origin").as[String]
url <- hCursor.downField("url").as[String]
} yield RootInterface("", headers, origin, url)
}
val secondRequest = sttp //.headers(("userId", USER_ID),("password","testpassword"))
.get(uri"http://httpbin.org/get")
secondRequest.send().body match {
case Left(fail) => System.out.println("The Get request was unsuccessful. " + fail)
case Right(rawJSONResponse) =>
parser.decode(rawJSONResponse) match {
case Left(fail) => System.out.println("The JSON response could not be parsed by Circe. " + fail)
case Right(rootInterfaceObject) =>
System.out.println("Origin :" + rootInterfaceObject.origin)
}
}
}
更新: 我现在正在尝试这个无济于事,
case class Headers(Accept: String, Accept_Encoding: String, Accept_Language: String, Host: String, Upgrade_Insecure_Requests: String, User_Agent: String)
case class RootInterface(args: String, headers: Headers, origin: String, url: String)
val doc = """{
"args": {},
"headers": {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "en-US,en;q=0.9",
"Host": "httpbin.org",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36"
},
"origin": "61.16.136.118, 61.16.136.118",
"url": "https://httpbin.org/get"
}"""
implicit val decodeHeaders: Decoder[Headers] = Decoder.forProduct6(
"Accept",
"Accept-Encoding",
"Accept-Language",
"Host",
"Upgrade-Insecure-Requests",
"User-Agent"
)(Headers(_, _, _, _, _, _))
implicit val decodeRootInterface: Decoder[RootInterface] = Decoder.forProduct4(
"args",
"headers",
"origin",
"url"
)(RootInterface(_, _, _, _))
val t = decode[RootInterface](doc)
我仍然遇到解码失败的问题。它看起来像是因为 args
字段。
我强烈建议您组合地构建您的实例——例如您可以定义一个单独的 Decoder[Headers]
实例,然后在您的 Decoder[RootInterface]
中使用它,而不是将所有 Headers
解码逻辑烘焙到 RootInterface
解码器中。
我还建议避免直接使用游标,除非您正在做一些您知道需要那种定义级别的特别复杂的事情。
所以给定这份文件:
val doc = """{
"args": {},
"headers": {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "en-US,en;q=0.9",
"Host": "httpbin.org",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36"
},
"origin": "61.16.136.118, 61.16.136.118",
"url": "https://httpbin.org/get"
}"""
…这些案例 classes:
case class Headers(Accept: String, Accept_Encoding: String, Accept_Language: String, Host: String, Upgrade_Insecure_Requests: String, User_Agent: String)
case class RootInterface(args: String, headers: Headers, origin: String, url: String)
…以下是您可以在 REPL 中使用的完整工作示例:
import io.circe.Decoder, io.circe.jawn.decode
implicit val decodeHeaders: Decoder[Headers] = Decoder.forProduct6(
"Accept",
"Accept-Encoding",
"Accept-Language",
"Host",
"Upgrade-Insecure-Requests",
"User-Agent"
)(Headers(_, _, _, _, _, _))
implicit val decodeRootInterface: Decoder[RootInterface] = Decoder.forProduct3(
"headers",
"origin",
"url"
)(RootInterface("", _, _, _))
……像这样:
scala> decode[RootInterface](doc)
res0: Either[io.circe.Error,RootInterface] = Right(RootInterface(,Headers(text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3,gzip, deflate,en-US,en;q=0.9,httpbin.org,1,Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36),61.16.136.118, 61.16.136.118,https://httpbin.org/get))
(我不确定 args
解码的目的是什么,所以我只是按照您使用空字符串的实现。)
不过,如果您控制 Headers
大小写 class 定义,我强烈建议您使用惯用的 Scala 成员名称(即驼峰式,而不是 upper snake)。在我看来,将其与 circe-derivation 相结合是一个非常明确的解决方案:
import io.circe.Decoder, io.circe.derivation.deriveDecoder
case class Headers(
accept: String,
acceptEncoding: String,
acceptLanguage: String,
host: String,
upgradeInsecureRequests: String,
userAgent: String
)
object Headers {
implicit val decodeHeaders: Decoder[Headers] = deriveDecoder(
_.replaceAll("([A-Z])", "-").capitalize
)
}
case class RootInterface(
args: Map[String, String],
headers: Headers,
origin: String,
url: String
)
object RootInterface {
implicit val decodeRootInterface: Decoder[RootInterface] = deriveDecoder
}
然后:
scala> io.circe.jawn.decode[RootInterface](doc)
res0: Either[io.circe.Error,RootInterface] = Right(RootInterface(Map(),Headers(text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3,gzip, deflate,en-US,en;q=0.9,httpbin.org,1,Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36),61.16.136.118, 61.16.136.118,https://httpbin.org/get))