播放Json - 复杂对象创建

时间:2017-01-10 00:45:49

标签: json scala playframework playframework-2.0

我试图在我的Play框架应用程序(Scala)中创建Json阅读器。问题是,我的Json的一部分有点时髦,需要进一步处理来检索值。例如:

{  
  "field1":"value1",
  "field2":"value/1",
  "num2":2
}

与案例类:

case class Field1(text: String, fields: Field2)
case class Field2(text: String, num: Int, num2: Int)

基本上,text的{​​{1}}和num字段是通过拆分文本从值Field2派生的。这是分离器功能:

value/1

这是相当简单的,实际的分离器功能要复杂得多。基本上,构造此对象def splitter(path: String, num2: Int): Field2 = { val split = path.split("\\") Field2(split(0), split(1).toInt, num2) } 的唯一方法是将单个字符串传递给吐出所需对象的函数。

如何为Field2(以及[{1}}的扩展名)创建阅读器?

这是我到目前为止所拥有的:

Field2

2 个答案:

答案 0 :(得分:0)

如果您使用非功能性组合子语法,我认为它变得更简单:

object Field2 {
  implicit val reader = Reads[Field2] { json =>
    for {
      path <- (json \ "field2").validate[String]
      num2 <- (json \ "num2").validate[Int]
    } yield splitter(path, num2)
  }
}

此外,如果您希望拆分器进一步验证输入,则返回JsResult[Field2],如下所示:

def splitter(path: String, num2: Int): JsResult[Field2] = {
  val split = path.split("\\")
  if (split.size != 2) {
    JsError(s"$path must be of the form: {field}\\{num}")
  } else {
    Try(Field2(split(0), split(1).toInt, num2)).map(JsSuccess(_)).getOrElse {
      JsError(s"${split(1)} is not a valid Int")
    }
  }
}

然后修改读者:

object Field2 {
  implicit val reader = Reads[Field2] { json =>
    for {
      path <- (json \ "field2").validate[String]
      num2 <- (json \ "num2").validate[Int]
      field2 <- splitter(path, num2)
    } yield field2
  }
}

如果您仍然喜欢使用功能语法,并且您不介意缺少验证功能,那么分割器会尝试这样做:

def splitter(path: String, num2: Int): Field2 = {
  val split = path.split("\\")
  Field2(split(0), split(1).toInt, num2)
}

implicit val reader = (
  (__ \ "field2").read[String] and
  (__ \ "num2").read[Int]
)(splitter _)

我建议不要这样做,它不安全(split(1)toInt都可能会抛出异常)并且功能语法可能会出现性能问题。请参阅https://www.lucidchart.com/techblog/2016/08/29/speeding-up-restful-services-in-play-framework/

答案 1 :(得分:0)

我不知道为什么你需要案例课程,但你也可以用你的需要转换json

 (__ \ "field2" \ "num2").json.copyFrom((__ \ "num2").json.pick) and
    (__ \ "field2").json.update(
      of[String].map { o =>
        val split = o.split("/")
        Json.obj(
          "text" -> split(0),
          "num" -> split(1).toInt
        )
      }
    )
  ).reduce andThen (__ \ "num2").json.prune

scala> j: play.api.libs.json.JsResult[play.api.libs.json.JsObject] = JsSuccess({"field2":{"num2":2,"text":"value","num":1},"field1":"value1"},/num2)

然后您可以使用Reads[Field1]