【问题标题】:Play 2.3 with Scala, converting JSON Array to Sequence用 Scala 玩 2.3,将 JSON Array 转换为 Sequence
【发布时间】:2014-09-01 12:06:57
【问题描述】:

欢迎,

我真的很想避免这种情况,但我现在放弃了。我正在尝试遍历 json 数组并提取一些元素并将它们排序。我尝试了很多选项,从播放文档中尝试了所有选项,多次尝试,但我仍然遇到相同的错误:当我的方法尝试撤回元素时出现空指针异常。所以我的json例子是:

[
  {
    "var1": "xx",
    "var2": "xxx",
    "var3": 111
  },
  {
    "var1": "yy",
    "var2": "yyy",
    "var3": 222 
  },
  {
    "var1": "zz",
    "var2": "zzz",
    "var3": 333    
  }
]

我定义了很多Reads的配置,最后一个是这样的但是不想编译;/

case class Vars1(vars: Seq[String])
val var1Reads: Reads[String] = (__ \ "var1").read[String]
implicit val vars1Reads: Reads[Vars1] = ((__).read[Seq[String]])(Vars1.apply _)

我想创建序列或列表,这并不重要,仅来自该数组的每个元素的 var1。它可以是纯序列,也可以是带有序列或其他的案例类。只是如何遍历 json 数组?我尝试了许多配置,读取 var1 是没有问题的,但是当我想从数组的每个元素中读取所有 vars 1 时,我就会遇到空指针异常。请,任何人都可以指出我一个好的方向,给我一个提示我做错了什么?请不要责怪我是编程新手,我开始学习scala和play框架。

感谢您的帮助。

更新:

我也试过这个:

implicit val vars1Reads = (__).read(Reads.list((__).read[String])).map( var => Vars(var))

但我仍然有同样的错误:

[NoSuchElementException: JsError.get]

【问题讨论】:

  • 声明你的阅读是懒惰的,例如,implicit lazy val vars1Reads。这是一个令人讨厌且完全令人困惑的 NPE 来源。

标签: json scala playframework-2.0


【解决方案1】:

解析这个最简单的方法是让Play把数组体解析为Seq[_],也就是一个对象序列。

我建议你的数组中的每个项目都应该用一个案例类来表示,例如

case class Var1(var1: String)

这提供了一种有用的类型,可以在其上添加对来自 JSON 的输入数据的验证。

您可以在适当的位置添加隐式Reads,例如

object Var1 {
  implicit val var1Reads: Reads[Var1] = {
    ((__ \ "var1").read[String]).map(Var1.apply _)
  }
}

请注意,读/写宏有一个限制,即它们不能以案例类具有单个字段的记录方式工作 - 请参阅http://grokbase.com/t/gg/play-framework/131bx7pcyd/play2-1-scala-json-writing-a-reads-writes-for-a-single-field-case-class - 这就是添加map 调用的原因。当有 2 个或更多字段时,宏应按文档说明工作。

然后您可以使用它来创建 Seq[Var1],例如

def test = Action(BodyParsers.parse.json) { request =>
  val result = request.body.validate[Seq[Var1]]
  ...
}

结果(这里我只是打印出result.toString的值)是:

$ curl --include --request POST --header "Content-type: application/json" --data '[{"var1": "3", "var2": "4"}, {"var1": "7"}]' http://localhost:9000/test
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Content-Length: 34

JsSuccess(List(Var1(3), Var1(7)),)

更新

如下面的 cmets 所述,您可以使用如下宏来简化 Reads[Var1] 实现:

implicit val var1Reads = Json.reads[Var1]

这只会做你想做的事,如果该字段被称为var1,即

case class Var1(var1: String)

【讨论】:

  • 根据docs,在2.1-RC2版本中修复了单字段案例类的限制。
  • 确实是这么说的。但是,((__ \ "var1").read[String])(Var1.apply _) 会导致编译错误Overloaded method value [read] cannot be applied to (String => controllers.Var1),而应用于多个字段的相同模式确实有效(使用 Play 2.3.4)。我目前的假设是,并非所有情况都已解决,但需要进行更多调查。
  • 啊,我认为修复的是宏生成,例如implicit val var1Reads = Json.reads[Var1]。我可以确认它有效。我发现宏生成足够可靠,我不需要自己编写。
  • 没错,所以在这种情况下,implicit val var1Reads = Json.reads[Var1] 确实可以正常工作。我认为这符合问题的要求,只要该字段名为var1
  • 这对我帮助很大。非常感谢您的帮助。它现在就像一个魅力,需要更少的代码,尤其是宏。再次感谢。我需要学习很多东西。
猜你喜欢
  • 2017-12-29
  • 1970-01-01
  • 2020-01-08
  • 2018-05-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-13
  • 1970-01-01
相关资源
最近更新 更多