Scala - 如何实现隐式 JSON reader
Scala - How to implement implicit JSON reader
我实施了隐式 Json 读取,以便从 JSON 读取两个字段,saleId 和 saleType。我想使 getSales 方法 return 相应地表示 saleId 和 saleType 的元组 (Int, String)。但是当我调用 getSales
方法时,出现以下错误:
Error:(46, 79) No JSON deserializer found for type (Int, String). Try to implement an implicit Reader or JsonFormat for this type.
val salesData = (salesJson \ "sales").as[(Int, String)]
Error:(46, 79) not enough arguments for method as: (implicit reader: org.json4s.Reader[(Int, String)], implicit mf: Manifest[(Int, String)])(Int, String).
Unspecified value parameters reader, mf.
val salesData = (salesJson \ "sales").as[(Int, String)]
我已经实现了隐式 Json 读起来真的和第一个错误混淆了。这是我的实现:
def getsales(context: SparkContext, saleId: Int): (Int, String)= {
val url= buildUrl(context, saleId)
implicit val salesReader: Reads[(Int, String)] = (
(__ \ "id_from_API").read[Int] and
(__ \ "sale_type").read[String]
).tupled
val salesJson: JValue = parse(httpStringResponse(url, context))
val salesData = (salesJson \ "sales_stats").as[(Int, String)]
salesData
}
关于您的代码的两个注意事项:
val salesData = (salesJson \ "sales").as[(Int, String)]
val salesData = (salesJson \ "sales_stats").as[(Int, String)]
可能必须相同。
您可能希望将 JsValue 放在行中而不是 JValue
val salesJson: JValue = parse(httpStringResponse(url, context))
除此之外,将您的 JSON reader 代码与其余代码分开测试可能会有所帮助。
以下对我有用:
import org.scalatest.WordSpec
import play.api.libs.functional.syntax._
import play.api.libs.json._
class ReadsExample extends WordSpec {
"read" in {
val sales =
"""
{
"sales_stats": {
"id_from_API": 42,
"sale_type": "cheap"
}
}
""".stripMargin
implicit val salesReader: Reads[(Int, String)] = (
(JsPath \ "id_from_API").read[Int] and
(JsPath \ "sale_type").read[String]
).tupled
val salesJson: JsValue = Json.parse(sales)
val salesData = (salesJson \ "sales_stats").as[(Int, String)]
}
}
请注意这里使用的play-json版本是2.3.10.
编辑
评论中问题的代码示例
import org.scalatest.WordSpec
import play.api.libs.json.Json.reads
import play.api.libs.json.{Json, _}
class ReadsExample extends WordSpec {
"read" in {
val sales =
"""
{
"id_from_API": 9,
"sale_type": {
"main" : "a",
"sub" : "b"
}
}
""".stripMargin
val salesJson: JsValue = Json.parse(sales)
val salesData = salesJson.as[Sales]
}
}
case class Sales(id_from_API: Int, sale_type: SaleType)
case class SaleType(main: String, sub: String)
object Sales {
implicit val st: Reads[SaleType] = reads[SaleType]
implicit val of: Reads[Sales] = reads[Sales]
}
我实施了隐式 Json 读取,以便从 JSON 读取两个字段,saleId 和 saleType。我想使 getSales 方法 return 相应地表示 saleId 和 saleType 的元组 (Int, String)。但是当我调用 getSales
方法时,出现以下错误:
Error:(46, 79) No JSON deserializer found for type (Int, String). Try to implement an implicit Reader or JsonFormat for this type.
val salesData = (salesJson \ "sales").as[(Int, String)]
Error:(46, 79) not enough arguments for method as: (implicit reader: org.json4s.Reader[(Int, String)], implicit mf: Manifest[(Int, String)])(Int, String).
Unspecified value parameters reader, mf.
val salesData = (salesJson \ "sales").as[(Int, String)]
我已经实现了隐式 Json 读起来真的和第一个错误混淆了。这是我的实现:
def getsales(context: SparkContext, saleId: Int): (Int, String)= {
val url= buildUrl(context, saleId)
implicit val salesReader: Reads[(Int, String)] = (
(__ \ "id_from_API").read[Int] and
(__ \ "sale_type").read[String]
).tupled
val salesJson: JValue = parse(httpStringResponse(url, context))
val salesData = (salesJson \ "sales_stats").as[(Int, String)]
salesData
}
关于您的代码的两个注意事项:
val salesData = (salesJson \ "sales").as[(Int, String)]
val salesData = (salesJson \ "sales_stats").as[(Int, String)]
可能必须相同。
您可能希望将 JsValue 放在行中而不是 JValue
val salesJson: JValue = parse(httpStringResponse(url, context))
除此之外,将您的 JSON reader 代码与其余代码分开测试可能会有所帮助。
以下对我有用:
import org.scalatest.WordSpec
import play.api.libs.functional.syntax._
import play.api.libs.json._
class ReadsExample extends WordSpec {
"read" in {
val sales =
"""
{
"sales_stats": {
"id_from_API": 42,
"sale_type": "cheap"
}
}
""".stripMargin
implicit val salesReader: Reads[(Int, String)] = (
(JsPath \ "id_from_API").read[Int] and
(JsPath \ "sale_type").read[String]
).tupled
val salesJson: JsValue = Json.parse(sales)
val salesData = (salesJson \ "sales_stats").as[(Int, String)]
}
}
请注意这里使用的play-json版本是2.3.10.
编辑
评论中问题的代码示例
import org.scalatest.WordSpec
import play.api.libs.json.Json.reads
import play.api.libs.json.{Json, _}
class ReadsExample extends WordSpec {
"read" in {
val sales =
"""
{
"id_from_API": 9,
"sale_type": {
"main" : "a",
"sub" : "b"
}
}
""".stripMargin
val salesJson: JsValue = Json.parse(sales)
val salesData = salesJson.as[Sales]
}
}
case class Sales(id_from_API: Int, sale_type: SaleType)
case class SaleType(main: String, sub: String)
object Sales {
implicit val st: Reads[SaleType] = reads[SaleType]
implicit val of: Reads[Sales] = reads[Sales]
}