保留Play框架表单映射数组中的空值

时间:2016-03-23 22:32:27

标签: arrays forms scala playframework optional

我试图了解如何强制Play Scala框架表单映射器在数组属性中保存空值。

实施例。请求正文(打印出下面的代码段):

AnyContentAsJson({
"entities":["ENI","GDF Suez","Procter & Gamble"],
"entityValues":[null,"42",null]
})

绑定后entityValues属性的结果值:

List(Some(42.0))

但我希望看到:

List(None, Some(42.0), None)

控制器的代码片段:

def actionX = Action {implicit request =>
  println(request.body)
  TaskForm.form.bindFromRequest.fold(
    formWithErrors => {
      BadRequest("error")
    },
    taskData => {
      println(taskData.entityValues)
    }
  )
}

带有映射的表单类:

case class TaskForm(entities: List[String],
                entityValues: List[Option[Double]]) { }

object TaskForm {
  val map = mapping(

    "entities" -> list(text),
    "entityValues" -> list(optional(of(doubleFormat)))

  )(TaskForm.apply)(TaskForm.unapply)

  val form = Form(
    map
  )
}

我还尝试了optionaldefault映射参数的某些组合,但结果仍然相同。

使用0或任何其他数字值代替null并非如此。

有没有人有任何想法如何实现这种表单行为?

提前感谢您的时间和关注。

1 个答案:

答案 0 :(得分:3)

您似乎正在将JSON发送到表单端点。虽然这个适用于简单的JSON结构,但是你无法控制它是如何完成的,因此会遇到像你所看到的那样的问题。

我明确表示要成为JSON端点,然后您可以定义自己的Reads[Option[Double]] 正是您想要的

首先,在Controller级别定义implicits;在这里我们可以控制null - 处理;它最终很容易:

implicit val optionalDoubleReads = new Reads[Option[Double]] {
  def reads(json: JsValue) = json match {
    case JsNumber(n) => JsSuccess(Some(n.toDouble))
    case JsString(n) => JsSuccess(Some(n.toDouble))
    case JsNull      => JsSuccess(None)             // The important one
    case _           => JsError("error.expected.jsnumber")
  }
}

implicit val taskReads = Json.reads[TaskForm]

完成上述操作后,我们会将您的Action修改为 require JSON(使用parse.json)。函数本身与原始的表单绑定fold

非常相似
 def actionX = Action(parse.json) { implicit request =>

   println(request.body)
   request.body.validate[TaskForm].fold(
     jsonErrors => {
       BadRequest(s"Error: $jsonErrors")
     },
     taskData => {
       println(taskData.entityValues)
       Ok(taskData.entityValues.toString)
     }
   )
 }