![](/img/trans.png)
[英]Add optional property with json transformers in playframework 2.4
[英]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”,在另一个案例中有一些字符串
我有Reader
和Writer
对象,但我不明白如何在阅读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]
,你的实际A
是String
所以你应该删除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" }
如果类型是user
或group
,则返回给出JsSuccess
的读取,否则返回JsError
。 从注释我们知道如果类型不是user
或group
,我们应该返回空字符串,读取可以变为:
(__ \ "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,你指的是我正确的方向。
flatMap
和filter
帮助我,我有
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.