繁体   English   中英

在Play 2.4中验证具有其他属性依赖性的json属性

[英]Validate json property with dependency of other property in Play 2.4

我有

case class AclRuleScope(kind: String, value: String)

我想要将Json转换为具有限制的AclRuleScope

type可能只是:“default”| “用户”| “团体”| “域”

如果type是“user”|,则value可能只是电子邮件 “group”,在另一个案例中有一些字符串

我有ReaderWriter对象,但我不明白如何在阅读value时获得type value

object AclRuleScope {

  implicit val aclRuleScopeRead = (
    (__ \ "type").read[String](pattern("^(default|user|group|domain)$".r)) and
      (__ \ "value").read[String](
          email keepAnd 
          filter(
              ValidationError("error.scope.value")
          )( ??? == JsString("user") || ??? == JsString("group")))
    )(this.apply _)

}

什么必须在???

JsConstraints#filter具有以下签名

def filter[A](otherwise: ValidationError)(p: A => Boolean)(implicit reads: Reads[A])

当你写作

filter(ValidationError("error.scope.value"))(??? == JsString("user") || ??? == JsString("group")))

代码(??? == JsString("user") || ??? == JsString("group"))实际上是要过滤的第二个参数,因此它应该是A => Boolean的谓词。 此外,因为这是在email读取后读取的,这是一个Reads[String] ,你的实际AString所以你应该删除JsString

您可以写的最小变化是:

implicit val aclRuleScopeRead = (
  (__ \ "type").read[String](pattern("^(default|user|group|domain)$".r)) and
    (__ \ "value").read[String](
      email keepAnd
        filter(
          ValidationError("error.scope.value")
        )(x => x == "user" || x == "group"))
  ).tupled

我强烈建议您将谓词提取到自己的方法:

def isValidEmail: (String) => Boolean = {
  x => x == "user" || x == "group"
}

把你的读物写成

implicit val aclRuleScopeRead = (
  (__ \ "type").read[String](pattern("^(default|user|group|domain)$".r)) and
    (__ \ "value").read[String](
      email keepAnd filter(ValidationError("error.scope.value"))(isValidEmail))
  ).tupled

你可以做得更好

val validEmail = email keepAnd filter(ValidationError("error.scope.value"))(isValidEmail))

和写

implicit val aclRuleScopeRead = (
  (__ \ "type").read[String](pattern("^(default|user|group|domain)$".r)) and
    (__ \ "value").read[String](validEmail)
  ).tupled

在评论中澄清后,如果类型为“user”或“group”,则只需要解析电子邮件,如果不是这样,则返回空字符串。

答案接近于这个问题中概述的解决方案

value字段的读取首先需要检查type字段的值。 类型字段上的条件如下所示:

(__ \\“type”)。read [String] .filter(ValidationError(“error.scope.value”))(isEmailType)

其中isEmailType定义为

def isEmailType: (String) => Boolean = { x => x == "user" || x == "group" }

如果类型是usergroup ,则返回给出JsSuccess的读取,否则返回JsError 从注释我们知道如果类型不是usergroup ,我们应该返回空字符串,读取可以变为:

(__ \ "type").read[String]
            .filter(ValidationError("error.scope.value"))(isEmailType)
            .orElse Reads.pure("")

哪个是安全的,永远不会返回JsError 这很好,因为有一个专用的reads来强制执行type验证,我们当前正在操作的读取仅作为value验证的一部分。 现在,如果解析是JsSuccess我们需要将read更改为parse value

(__ \ "type").read[String]
            .filter(ValidationError("error.scope.value"))(isEmailType)
            .flatMap(_ => (__ \ "value").read[String](email))
            .orElse Reads.pure("")

使用flatMap,如果type读取成功,我们将通过正确读取value替换type读取。

谢谢@Jean,你指的是我正确的方向。

flatMapfilter帮助我,我有

case class AclRuleScope(kind: String, value: Option[String])

val aclRuleScopeRead = (
    (__ \ "type").read[String] and
    (__ \ "type").read[String](pattern("^(default|user|group|domain)$".r)).flatMap {
      case t if "user".equals(t) || "group".equals(t) =>
        (__ \ "value").readNullable[String](email)
          .filter(ValidationError(s"error.acl.scope.value omitted for '$t' type"))(_.isDefined)
          .filter(ValidationError(s"error.acl.scope.value not defained for '$t' type"))(_.exists(_.nonEmpty))
      case "domain" =>
        (__ \ "value").readNullable[String]
          .filter(ValidationError("error.acl.scope.value omitted for 'domain' type"))(_.isDefined)
          .filter(ValidationError("error.acl.scope.value not defained for 'domain' type"))(_.exists(_.nonEmpty))
      case "default" =>
        (__ \ "value").readNullable[String]
          .filter(ValidationError("error.acl.scope.value must be omitted for 'default' type"))(_.isEmpty)
    }
)(AclRuleScope.apply _)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM