Scala - convert String to Json using Play json

爷,独闯天下 提交于 2019-12-08 03:59:53

问题


I need help to parse a json string into scala class using playJson

I wrote a formatter but I don't know how to handle the nested arrays.

Where Document Case class is

case class Document(content: String, score: Double, size: Int, path:String)

and formatter

implicit val similarHashFormatter: Format[SimilarHash] = (
  ((__ \ "hits" \ "hits" \\ "fields")(0) \ "content_hash")(0).format[String] and
  (__ \ "hits"  \ "hits" \\ "_score").format[Double] and
  ((__ \ "hits" \ "hits" \\  "fields")(0) \ "ast_size")(0).format[Int] and
  ((__ \ "hits" \ "hits" \\ "fields")(0) \ "path")(0).format[String]
) (SimilarHash.apply, unlift(SimilarHash.unapply))

This is my source json

{
  "hits": {
    "hits": [
      {
        "score": 1.5204661,
        "fields": {
          "size": [
            557645
          ],
          "path": [
            "/user/ubuntu/app
          ],
          "content": [
            "images"
          ]
        }
      },
      {        
        "score": 1.5199462,
        "fields": {
          "size": [
            556835
          ],
          "path": [
            "/user/ubuntu/app
          ],
          "content": [
            "documents"
          ]
        }
      }
    ]
  }
}

Any idea ?


回答1:


You could do this by creating custom Reads separately for each field as follow:

  import play.api.libs.json._
  import play.api.libs.functional.syntax._

  case class Document(content: String, score: Double, size: Int, path:String)

  val jsonString = """{
                         "hits": {
                             "hits": [
                                 {
                                     "score": 1.5204661,
                                     "fields": {
                                         "size": [
                                             557645
                                         ],
                                         "path": [
                                             "/user/ubuntu/app"
                                         ],
                                         "content": [
                                             "images"
                                         ]
                                     }
                                 },
                                 {
                                     "score": 1.5199462,
                                     "fields": {
                                         "size": [
                                             556835
                                         ],
                                         "path": [
                                             "/user/ubuntu/app"
                                         ],
                                         "content": [
                                             "documents"
                                         ]
                                     }
                                 }
                             ]
                         }
                     }"""

  val playJson = Json.parse(jsonString)

  val contentReads = new Reads[String] {
    override def reads(json: JsValue): JsResult[String] = json \ "hits" match {
      case JsDefined(o: JsObject) =>
        o \ "hits" match {
          case JsDefined(arr: JsArray) =>
            arr.value.head \ "fields" match {
              case JsDefined(fieldObj: JsObject) =>
                fieldObj \ "content" match {
                  case JsDefined(contentArr: JsArray) =>
                    JsSuccess(Json.stringify(contentArr.value.head))
                  case _ => JsError( """Can't read hits \ hits \ fields \ content""")
                }
              case _ => JsError( """Can't read hits \ hits \ fields""")
              case _ => JsError( """Can't read hits \ hits""")
            }
          case _ => JsError("Can't read hits")
        }
    }
  }

  val sizeReads = new Reads[Int] {
    override def reads(json: JsValue): JsResult[Int] = json \ "hits" match {
      case JsDefined(o: JsObject) =>
        o \ "hits" match {
          case JsDefined(arr: JsArray) =>
            arr.value.head \ "fields" match {
              case JsDefined(fieldObj: JsObject) =>
                fieldObj \ "size" match {
                  case JsDefined(contentArr: JsArray) =>
                    JsSuccess(Json.stringify(contentArr.value.head).toInt)
                  case _ =>  JsError("""Can't read hits \ hits \ fields \ size""")
                }
              case _ => JsError("""Can't read hits \ hits \ fields""")
            }
          case _ => JsError("""Can't read hits \ hits""")
        }
      case _ => JsError("Can't read hits")
    }
  }

  val scoreReads = new Reads[Double] {
    override def reads(json: JsValue): JsResult[Double] = json \ "hits" match {
      case JsDefined(o: JsObject) =>
        o \ "hits" match {
          case JsDefined(arr: JsArray) =>
            arr.value.head \ "score" match {
              case JsDefined(score: JsValue) =>
                JsSuccess(Json.stringify(score).toDouble)
              case _ =>  JsError("""Can't read hits \ hits \ score""")
            }
          case _ => JsError("""Can't read hits \ hits""")
        }
      case _ => JsError("Can't read hits")
    }
  }

  val pathReads = new Reads[String] {
    override def reads(json: JsValue): JsResult[String] = json \ "hits" match {
      case JsDefined(o: JsObject) =>
        o \ "hits" match {
          case JsDefined(arr: JsArray) =>
            arr.value.head \ "fields" match {
              case JsDefined(fieldObj: JsObject) =>
                fieldObj \ "path" match {
                  case JsDefined(contentArr: JsArray) =>
                    JsSuccess(Json.stringify(contentArr.value.head))
                  case _ =>  JsError("""Can't read hits \ hits \ fields \ path""")
                }
              case _ => JsError("""Can't read hits \ hits \ fields""")
            }
          case _ => JsError("""Can't read hits \ hits""")
        }
      case _ => JsError("Can't read hits")
    }
  }

  implicit val documentReads: Reads[Document] = (
  contentReads and
  scoreReads and
  sizeReads and
  pathReads
  )(Document.apply _)

  val document = playJson.validate[Document].get
//result: Document("images",1.5204661,557645,"/user/ubuntu/app")



回答2:


I figured out the solution based on oblivion's comment but without creating multiple reads.

  implicit val docReader: Reads[Document] = (
        (__ \ "fields" \ "content")(0).read[String] and
        (__  \ "_score").read[Double] and
        ((__ \  "fields") \ "size")(0).read[Int] and
        ((__ \ "fields") \ "path")(0).read[String]
      ) (Document.apply _)


  implicit val docsReader: Reads[Documents] = (
      (__ \ "hits" \ "max_score").read[Double] and
      (__ \ "hits" \ "hits").read[Seq[Document]]
    ) (Documents.apply _)

... and finally

val response = Json.parse(inputStream).asOpt[Documents]


来源:https://stackoverflow.com/questions/42168817/scala-convert-string-to-json-using-play-json

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!