将 JSON 映射到 Scala 对象的最有效方法是什么?

What is the most efficient way to map JSON to Scala Objects?

我想用 Play 库解析一些 "complex" JSON。

import play.api.libs.json._

让我们假设我从服务器获得了一个包含许多 JSON 对象的数组,我无法对其进行修改。每个条目看起来都与这个相似:

{
  "id": 1,
  "urn": "urn:article:5",
  "key": "post",
  "foo": "useless"
}

最后我想将这个结构映射到具有以下值的 Scala 对象中:

最有效的方法是什么?将 JSON 框架内的结构映射到我的需要,或者应该尽快使用中间案例 classes 将它们映射到我的自定义结构中?

我翻了一下official documentation,不过他们好像没有讨论这个问题。

目前我会创建一个中间案例 class,它只是从 JSON 中提取相关属性(id、urn、key)并在接下来的步骤中将这些对象映射到自定义我想要的结构。不知何故,我觉得这不是要走的路。

您可以在自定义 Reads/Writes 序列化程序中添加这种逻辑。请参阅我关于如何添加自定义 JSON Writer for Seq of Tuple 的回答。在那种情况下,我做一个 Writes,在你的情况下,你会创建一个 Reads,因为你正在阅读 JSON 并转换为 class 的实例,很可能是一个案例class.

例如

case class Wombat(id: Int, urn: String, `type`: String)
implicit val myWombatReads = new Reads[Wombat] {
  def reads(js: JsValue): JsResult[Wombat] = {
    val id = (js \ "id").as[Int]
    val urn = (js \ "urn").as[String]
    val key = (js \ "key").as[String]
    JsSuccess(Wombat(id, urn, urn.split(":")(1) + "_" + key))
  }
}

我没有测试您的自定义逻辑,但您明白了。您还可以添加验证器等。

你需要使用Json transformer

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

val t =  (

  (__ \ "id").json.copyFrom( (__ \ "id").json.pick) and
    (__ \ "urn").json.copyFrom( (__ \ "urn").json.pick) and
    ( __ \ "type").json.copyFrom(
      (__ \ "urn").read[String].flatMap(urn =>
        (__ \ "key").read[String].map(key =>
          JsString(urn.split(":")(1) + "_" + key)
        )
      )
    )
  ).reduce

你例子的转换结果:

json.transform(t)

scala> json: play.api.libs.json.JsValue = {"id":1,"urn":"urn:article:5","key":"post","foo":"useless"}

scala> res2: play.api.libs.json.JsResult[play.api.libs.json.JsObject] = JsSuccess({"id":1,"urn":"urn:article:5","type":"article_post"},)

您还可以添加一些验证。 coast-to-coast desig.

的好文章