在Hibernate Validator 4.x中是否有跨字段验证的实现(或第三方实现)?如果不是,实现跨字段验证器的最干净的方法是什么?
例如,如何使用API来验证两个bean属性是否相等(例如验证密码字段与密码验证字段是否匹配)。
在注释中,我期望如下内容:
public class MyBean {
@Size(min=6, max=50)
private String pass;
@Equals(property="pass")
private String passVerify;
}
我建议你另一种可能的解决办法。也许不那么优雅,但更容易!
public class MyBean {
@Size(min=6, max=50)
private String pass;
private String passVerify;
@NotNull
private LocalDate passExpiry;
@NotNull
private LocalDate dateOfJoining;
@AssertTrue(message = "Fields `pass` and `passVerify` should be equal")
// Any method name is ok als long it begins with `is`
private boolean isValidPass() {
//return pass == null && passVerify == null || pass.equals(passVerify);
// Since Java 7:
return Objects.equals(pass, passVerify);
}
@AssertTrue(message = "Field `passExpiry` should be later than `dateOfJoining`")
// Other rules can also be validated in other methods
private boolean isPassExpiryAfterDateOfJoining() {
return dateOfJoining.isBefore(passExpiry);
}
}
isValid()和isPassExpiryAfterDateOfJoining()方法由验证器自动调用。在ConstraintViolations中报告的属性路径将从方法名中提取:valid和passExpiryAfterDateOfJoining。
我没有评论第一个答案的名声,但我想补充的是,我已经为获胜的答案添加了单元测试,并有以下观察:
如果第一个或字段名出错,就会出现验证错误,就好像值不匹配一样。不要被拼写错误绊倒。
@FieldMatch(first=“invalidFieldName1”, second=“validFieldName2”)
验证器将接受等效的数据类型,即这些都将通过FieldMatch:
private String stringField = "1";
private Integer integerField = new Integer(1)
private int intField = 1;
如果字段的对象类型没有实现equals,则验证将失败。
使用Hibernate Validator 4.1.0。最后,我建议使用@ScriptAssert。除了它的JavaDoc:
脚本表达式可以用任何脚本或表达式编写
JSR 223(“java平台脚本编写”)
兼容的引擎可以在类路径中找到。
注意:评估是由运行在Java VM中的脚本“引擎”执行的,因此是在Java“服务器端”,而不是在某些注释中所述的“客户端”。
例子:
@ScriptAssert(lang = "javascript", script = "_this.passVerify.equals(_this.pass)")
public class MyBean {
@Size(min=6, max=50)
private String pass;
private String passVerify;
}
或者使用更短的别名和null安全:
@ScriptAssert(lang = "javascript", alias = "_",
script = "_.passVerify != null && _.passVerify.equals(_.pass)")
public class MyBean {
@Size(min=6, max=50)
private String pass;
private String passVerify;
}
或者使用Java 7+ null-safe Objects.equals():
@ScriptAssert(lang = "javascript", script = "Objects.equals(_this.passVerify, _this.pass)")
public class MyBean {
@Size(min=6, max=50)
private String pass;
private String passVerify;
}
尽管如此,自定义类级验证器@Matches解决方案并没有什么问题。