2015-12-14 107 views
2

验证JSON属性与播放2.4

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

,我想转换JsonAclRuleScope有限制的其他财产的依赖性:

type可能只有:“默认” | “用户”| “组”| “domain”

value如果type为“user”,则可能只有电子邮件| “群”,而在另一个案件

我有对象与ReaderWriter,但我不能明白,我怎么能得到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 _) 

} 

必须是什么???

回答

1

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 

在澄清的意见,你只希望如果类型是“用户”或“集团”返回一个空字符串,如果不是这样解析电子邮件。

答案是接近this question

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

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

其中isEmailType被定义为

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

这将返回一个读,给出了一个JsSuccess如果类型是usergroupJsError否则,从评论,我们知道,我们应该返回空字符串,如果该类型不是usergroup,在读可以成为:

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

是一种安全,绝不会返回一个JsError。这很好,因为有专门的reads来强制type验证,我们目前操作的读取仅作为验证的一部分value。 现在,我们需要改变读取解析value如果解析是JsSuccess

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

使用flatMap,我们更换type读取由上value正确读取如果type读取是成功的。

+0

validEmail将测试(__ \ “值”)?因为“用户”||,验证将是错误的“组”不是有效的电子邮件。如果(__ \“type”)等于“user”||,我想测试(__ \“value”)是仅限电子邮件“组”。我需要'???'作为(__ \“type”)的值 –

+0

噢好吧抱歉,我想我明白你的意思是它将会变长:)如果类型是别的东西,只要一个字符串? – Jean

+0

for'default'type - 空字符串,'domain'类型 - (__ \“value”)值。其他类型受(__ \“type”)读取限制。 –

0

谢谢@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 _)