代码之家  ›  专栏  ›  技术社区  ›  samba

scala-如何实现隐式JSON阅读器

  •  0
  • samba  · 技术社区  · 6 年前

    我已经实现了隐式JSON读取,以便从JSON、saleid和saletype中读取两个字段。我想让getsales方法返回一个表示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
    }
    
    1 回复  |  直到 6 年前
        1
  •  1
  •   étienne    6 年前

    关于您代码的两个注意事项:

    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阅读器代码和其他代码可能会有所帮助。

    以下内容对我很有用:

    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]
    }