【问题标题】:Append type level validation error message to specific field将类型级别验证错误消息附加到特定字段
【发布时间】:2014-01-19 21:29:56
【问题描述】:

我有一个简单的类,它使用boolean isValid() 方法进行了验证,该方法有效,当然错误消息是在类/类型级别。

这是我的简单课程:

public class NewPasswordDTO {
    @NotNull
    public String password;

    @NotNull
    public String confirmation;

    @AssertTrue(message="Passwords must match.")
    protected boolean isValid() {
        return password.equals(confirmation);
    }
}

但我真正想要的是这样的:

public class NewPasswordDTO {
    @NotNull
    @Equals("confirmation", message="...")
    public String password;

    @NotNull
    public String confirmation;
}

因此错误消息将设置在字段级别而不是类/类型级别。

这有可能吗?也许为该类使用自定义验证器?

提前致谢!

解决方案:

感谢贡纳尔!我刚刚想出了一个很好的通用解决方案:-)。我只是使用(意味着复制和粘贴)来自 Hibernates @ScriptAssertScriptAssertValidator 的代码并稍作修改:

@ScriptAssert:

  • 添加新的String field()。 (这是附加错误消息的地方)

ScriptAssertValidator:

  • initialize方法中,确保同时保存fieldNamemessage属性,因为我们需要在下一步中访问它们

  • isValid方法的底部添加这个sn-p:

    context.buildConstraintViolationWithTemplate(errorMessage) .addPropertyNode(fieldName).addConstraintViolation();

  • 还要在 isValid 方法内的某处添加 context.disableDefaultConstraintViolation(); 以不生成默认错误消息,否则将在类级别附加。

就是这样。现在我可以这样使用它了:

@FieldScriptAssert(lang="javascript", script="_this.password.equals(_this.confirmation)", field="password", message="...")
public class NewPasswordDTO { ... }

【问题讨论】:

    标签: java validation bean-validation hibernate-validator


    【解决方案1】:

    您可以在类上使用 @ScriptAssert 约束(请注意,约束应该始终没有副作用,因此更改已验证 bean 的状态不是一个好主意;相反,您应该检查是否两个字段匹配)或者您实现自定义类级约束。

    后者also allows 指向约束违规的自定义属性路径,它允许将“确认”属性标记为错误而不是完整的类。

    【讨论】:

    • 这是个好消息!我会检查的。顺便提一句。我尝试使用@ScriptAssert 更改状态,但没用。调试日志总是看起来像:some field constraint checkedsome other field constraint checked...class constraint checked。所以没有机会触发一些字段级别的约束。
    【解决方案2】:

    简单的答案:不是(除非您实现它):http://docs.oracle.com/javaee/6/api/javax/validation/constraints/package-summary.html 显示所有注释约束。 当然,您可以通过@producer 等将您的字符串作为资源注入您的类中(最近讨论将在 jdk8 中删除),但您不能将此值用于您的断言。
    回复评论:
    这是假设性质是一个常量字符串,您想将其用作字符串资源。然后当然可以使用 @Producer 编写您自己的基于 java.lang.string 的类,然后是 @Inject -有能力的。虽然这肯定不是我个人处理常量字符串的方式。

    【讨论】:

    • 谢谢。我知道所有这些注释,问题更像是:我可以编写自己的注释/验证器来处理这个问题吗? ......而且我真的不明白你的意思是“当然你可以通过@producer等将你的字符串作为资源注入你的班级”。你有例子吗?
    • 哇,这听起来真的很像 baaaad hack :-D。甚至不可能以某种方式使用@ScriptAssert(...) 来完成我的任务吗? ...(它也很脏,但是)也许有可能做这样的事情:@ScriptAssert(lang="javascript", script="if(!_this.password.equals(_this.confirmation)) password=''; return true;")。然后我会在password 进行一些@NotEmpty 检查,它会捕获新引发的错误......
    • 我在顶部附加了我的自定义解决方案。我决定使用@ScriptAssert 的逻辑,而不是不灵活的自定义注解。太棒了!!
    【解决方案3】:

    如果您使用的是 Spring 框架,那么作为使用 JSR 223 脚本的 @ScriptAssert 的替代方案,您可以使用使用 Spring 表达式语言 (SpEL) 的 @SpELAssert。优点是它不需要任何符合 JSR 223 的脚本引擎,这在某些环境中可能不可用。请参阅this answer 了解更多信息。

    【讨论】:

    • 谢谢。这听起来也不错。您提供的代码非常小,查看测试用例似乎使用的表达式与那些 javascript 表达式非常相似。 ...你能告诉我哪个环境不支持 JSR 223 吗?我认为它是 Java 版本 6 的一部分?
    猜你喜欢
    • 2012-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多