Playframework - JSON 解析具有单个字段的对象 - 定义问题

Playframework - JSON parsing object with single field - definition issue

当反序列化对象只有一个字段时,我找不到如何让它工作的方法 - 我无法编译代码。似乎 and 运算符做了一些转换,我找不到调用方法来做同样的事情。

我关注json:

{"total": 53, "max_score": 3.2948244, "hits": [
                                 {
                                     "_index": "h",
                                     "_type": "B",
                                     "_id": "3413569628",
                                     "_score": 3.2948244,
                                     "_source": {
                                         "fotky": [
                                             {
                                                 "popisek":" ",
                                                 "localFileSystemLocation":" ",
                                                 "isMain": true,
                                                 "originalLocation": ""
                                             }
                                         ]
                                     }
                                 }
                             ]
}

我尝试将以下数据模型反序列化为:

case class SearchLikeThisResult(total: Int, max_score: Double, hits: Seq[Hits])

case class Hits(_index: String, _type: String, _id: String, _score: Double, _source: Source)

case class Source(fotky: Seq[Photo])

case class Photo(isMain: Boolean, originalLocation: Option[String], localFileSystemLocation: Option[String], popisek: Option[String])

隐式如下:

object SearchLikeThisHits {

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

  implicit val photoReads: Reads[Photo] = (
    (JsPath \ "isMain").read[Boolean] and
      (JsPath \ "originalLocation").readNullable[String] and
      (JsPath \ "localFileSystemLocation").readNullable[String] and
      (JsPath \ "popisek").readNullable[String]
    )(Photo.apply _)    

  implicit val sourceReads: Reads[Source] = (
    (JsPath \ "fotky").read[Seq[Photo]]
    )(Source.apply _)

  implicit val hitsReads: Reads[Hits] = (
    (JsPath \ "_index").read[String] and
      (JsPath \ "_type").read[String] and
      (JsPath \ "_id").read[String] and
      (JsPath \ "_score").read[Double] and
      (JsPath \ "_source").read[Source]
    )(Hits.apply _)

  implicit val searchLikeThisResult: Reads[SearchLikeThisResult] = (
    (JsPath \ "total").read[Int] and
      (JsPath \ "max_score").read[Double] and
      (JsPath \ "hits").read[Seq[Hits]]
    )(SearchLikeThisResult.apply _)
}

我真正纠结的是_source:

  implicit val sourceReads: Reads[Source] = (
    (JsPath \ "fotky").read[Seq[Photo]]
    )(Source.apply _)

其中读取被报告为未知符号 - 在其他情况下 and 执行一些转换。 内联定义也无济于事。

有人遇到过这个问题吗?

您可以通过使用 Json.reads 自动生成您的 Reads 来省去一些麻烦(前提是 class 的定义与 Json 对象完全相同- 这就是你的情况)。

implicit val photoReads = Json.reads[Photo]
implicit val sourceReads = Json.reads[Source]
implicit val hitsReads = Json.reads[Hits]
implicit val searchResultReads = Json.reads[SearchLikeThisResult]

有关详细信息,请参阅 https://www.playframework.com/documentation/2.1.1/ScalaJsonInception

花哨的应用程序构建器语法(and 等)很不错,但它可能掩盖了 Reads 是一元的并且与 map 完美配合的事实,flatMap, for-理解等

因此,虽然应用构建器语法不适用于单个值,但普通的旧 map 可以:

implicit val sourceReads: Reads[Source] =
  (JsPath \ "fotky").read[Seq[Photo]].map(Source(_))

这里的关键是 (JsPath \ "fotky").read[Seq[Photo]] 是一个 Reads[Seq[Photo]],而你想要一个 Reads[Source]map 为您提供了一种从一个到另一个的方法,就像您可以使用它来将 Option[Seq[Photo]] 转换为 Option[Source,例如。