簡體   English   中英

如何使用 Json4s 從 Json 中提取我的案例類?

[英]How to extract my case class from Json using Json4s?

在 akka scala 應用程序中,我使用了一個休息端點。 因此,我想將它的響應映射到案例類,但我也想通過轉換某些屬性來簡化這些案例類的工作,例如那些包含日期的屬性。

所以給定一個 Json:

{
    "id": "20180213165959sCdJr",
    "createdAt": "2018-02-13T16:59:59.570+0000",
    "finishedAt": "2018-02-13T17:00:18.118+0000"
}

我想從中創建這樣一個類:

case class FinishedRun
(
  id: String,
  createdAt: Date,
  finishedAt: Date
)

我創建了這個構造函數:

object FinishedRun {

  def apply(id: String,
            createdAt: String,
            finishedAt: String
           ): FinishedRun = {

    val getDate = (jsonValue: String) => {
      val format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
      format.parse(jsonValue)
    }


    new FinishedRun(id, createdAt = getDate(createdAt), finishedAt = getDate(finishedAt))
  }
}

雖然這適用於從頭開始初始化案例類,但我無法在 json4s 庫的幫助下通過parse(json).as[FinishedRun]方法提取這個案例類。

看來 json4s 沒有調用案例類的構造函數,因此無法提取它,拋出:

No usable value for createdAt
Invalid date '2018-02-13T16:59:59.570+0000'
org.json4s.package$MappingException: No usable value for createdAt
Invalid date '2018-02-13T16:59:59.570+0000'
    at org.json4s.reflect.package$.fail(package.scala:95)

我錯過了什么讓 Json4s 正確解析日期?


這是我的測試用例:

import org.json4s._
import org.json4s.native.JsonMethods._
import org.scalatest.FlatSpec


class MarshallingTest extends FlatSpec {
  implicit val formats = DefaultFormats

  it should "marshall json object with date iso strings into a case class with Date properties" in {
    val json =
      """
        |{
        |    "id": "20180213165959sCdJr",
        |    "createdAt": "2018-02-13T16:59:59.570+0000",
        |    "finishedAt": "2018-02-13T17:00:18.118+0000"
        |}
      """.stripMargin

    val expected = FinishedRun(
      id = "20180213165959sCdJr",
      createdAt = "2018-02-13T16:59:59.570+0000",
      finishedAt = "2018-02-13T17:00:18.118+0000"
    )
    val actual = parse(json).extract[FinishedRun]

    assert(actual == expected)
  }
}

您需要定義您的CustomSerializer(1)CustomSerializer(2) 我將日期類型從Date更改為ZonedDateTime

import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter

import org.json4s._
import org.json4s.JsonAST._
import org.json4s.JsonDSL._
import org.json4s.native.JsonMethods._
import org.scalatest.FlatSpec

case class FinishedRun
(
  id: String,
  createdAt: ZonedDateTime,
  finishedAt: ZonedDateTime
)

object FinishedRunSerializer {
  val dateTimeFmt = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
}

class FinishedRunSerializer extends CustomSerializer[FinishedRun](
  format => ( {
    case jObj: JObject =>
      implicit val fmt = format
      val id = (jObj \ "id").extract[String]
      val created = ZonedDateTime.parse((jObj \ "createdAt").extract[String],
        FinishedRunSerializer.dateTimeFmt)
      val finished = ZonedDateTime.parse((jObj \ "finishedAt").extract[String],
        FinishedRunSerializer.dateTimeFmt)
      FinishedRun(id, created, finished)
  }, {
    case finishedRun: FinishedRun =>
      ("id" -> finishedRun.id) ~
        ("createdAt" -> finishedRun.createdAt.format(FinishedRunSerializer.dateTimeFmt)) ~
        ("finishedAt" -> finishedRun.finishedAt.format(FinishedRunSerializer.dateTimeFmt))
  }
  ))

在你的測試或者使用的地方不要忘記帶FinishedRunSerializer

implicit val formats = DefaultFormats + new FinishedRunSerializer()

您的問題的一個簡單解決方案可能是使用org.json4s 中Serialization trait。 你應該能夠做這樣的事情:

val finishedRun = read[FinishedRun](json)

有關詳細信息和示例,請參閱此鏈接: https : //github.com/json4s/json4s#serializing-polymorphic-lists

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM