我正在使用grails 2.2.1并尝试验证嵌套命令结构。下面是我的命令对象的简化版本:
@Validateable
class SurveyCommand {
SectionCommand useful
SectionCommand recommend
SurveyCommand() {
useful = new SectionCommand(
question: 'Did you find this useful?',
isRequired: true)
recommend = new SectionCommand(
question: 'Would you recommend to someone else?',
isRequired: false)
}
}
@Validateable
class SectionCommand {
String question
String answer
boolean isRequired
static constraints = {
answer(validator: answerNotBlank, nullable: true)
}
static answerNotBlank = { String val, SectionCommand obj ->
if(obj.isRequired) {
return val != null && !val.isEmpty()
}
}
}
当我尝试验证SurveyCommand
的实例时,无论section值如何,它总是返回true
,并且我在SectionCommand
(answerNotBlank
)中的自定义验证器从未调用。从grails文档来看,似乎支持这种嵌套结构(deepValidate
默认为true)。然而,也许这条规则只适用于域对象,而不是命令对象?还是我漏掉了什么?
对于Grails 2.3和以后的版本,我发现级联验证插件很好地解决了这个问题。它定义了一个名为cascade的新验证器类型,它的功能完全符合您的期望。安装后,您的示例将变成:
class SurveyCommand {
...
static constraints = {
useful(cascade: true)
recommend(cascade: true)
}
}
您可以在主命令对象中添加一个自定义验证器
@Validateable
class SurveyCommand {
SectionCommand useful
SectionCommand recommend
static subValidator = {val, obj ->
return val.validate() ?: 'not.valid'
}
static constraints = {
useful(validator: subValidator)
recommend(validator: subValidator)
}
SurveyCommand() {
useful = new SectionCommand(
question: 'Did you find this useful?',
isRequired: true)
recommend = new SectionCommand(
question: 'Would you recommend to someone else?',
isRequired: false)
}
}
如果您试图使用mockForConstraintsTest()
从unit
测试中测试validation
,那么您应该在Config.groovy
中注册command
对象,而不是使用@Validateable
,因为现有的Grails错误。详细信息请参考以下问题/答案。
可以在Config.groovy
grails.validateable.classes =
[yourpackage.SurveyCommand, yourpackage.SectionCommand]