Java 基元集合的Hibernate验证
我希望能够做到以下几点:Java 基元集合的Hibernate验证,java,collections,bean-validation,hibernate-validator,Java,Collections,Bean Validation,Hibernate Validator,我希望能够做到以下几点: @Email public List<String> getEmailAddresses() { return this.emailAddresses; } @电子邮件 公共列表getEmailAddresses() { 返回此电子邮件地址; } 换句话说,我希望列表中的每个项目都被验证为电子邮件地址。当然,这样注释集合是不可接受的 有办法做到这一点吗?JSR-303和Hibernate Validator都没有现成的约束可以验证集合的每个元素 解
@Email
public List<String> getEmailAddresses()
{
return this.emailAddresses;
}
@电子邮件
公共列表getEmailAddresses()
{
返回此电子邮件地址;
}
换句话说,我希望列表中的每个项目都被验证为电子邮件地址。当然,这样注释集合是不可接受的
有办法做到这一点吗?JSR-303和Hibernate Validator都没有现成的约束可以验证集合的每个元素 解决此问题的一个可能的解决方案是创建自定义
@ValidCollection
约束和相应的验证器实现ValidCollectionValidator
要验证集合的每个元素,我们需要一个Validator
内部ValidCollectionValidator
的实例;为了获得这样的实例,我们需要定制ConstraintValidatorFactory
的实现
看看你是否喜欢下面的解决方案
简单地说
- 复制粘贴所有这些java类(并导入相关类)李>
- 在类路径上添加验证api、hibenate验证程序、slf4j-log4j12和testng JAR李>
- 运行测试用例
public @interface ValidCollection {
Class<?> elementType();
/* Specify constraints when collection element type is NOT constrained
* validator.getConstraintsForClass(elementType).isBeanConstrained(); */
Class<?>[] constraints() default {};
boolean allViolationMessages() default true;
String message() default "{ValidCollection.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
public class CollectionElementBean {
/* add more properties on-demand */
private Object notNull;
private String notBlank;
private String email;
protected CollectionElementBean() {
}
@NotNull
public Object getNotNull() { return notNull; }
public void setNotNull(Object notNull) { this.notNull = notNull; }
@NotBlank
public String getNotBlank() { return notBlank; }
public void setNotBlank(String notBlank) { this.notBlank = notBlank; }
@Email
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}
CollectionElementBean
public @interface ValidCollection {
Class<?> elementType();
/* Specify constraints when collection element type is NOT constrained
* validator.getConstraintsForClass(elementType).isBeanConstrained(); */
Class<?>[] constraints() default {};
boolean allViolationMessages() default true;
String message() default "{ValidCollection.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
public class CollectionElementBean {
/* add more properties on-demand */
private Object notNull;
private String notBlank;
private String email;
protected CollectionElementBean() {
}
@NotNull
public Object getNotNull() { return notNull; }
public void setNotNull(Object notNull) { this.notNull = notNull; }
@NotBlank
public String getNotBlank() { return notBlank; }
public void setNotBlank(String notBlank) { this.notBlank = notBlank; }
@Email
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}
ConstraintValidatorFactoryImpl
public class ConstraintValidatorFactoryImpl implements ConstraintValidatorFactory {
private ValidatorContext validatorContext;
public ConstraintValidatorFactoryImpl(ValidatorContext nativeValidator) {
this.validatorContext = nativeValidator;
}
@Override
public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> key) {
T instance = null;
try {
instance = key.newInstance();
} catch (Exception e) {
// could not instantiate class
e.printStackTrace();
}
if(ValidatorContextAwareConstraintValidator.class.isAssignableFrom(key)) {
ValidatorContextAwareConstraintValidator validator = (ValidatorContextAwareConstraintValidator) instance;
validator.setValidatorContext(validatorContext);
}
return instance;
}
}
注意:-当bean有约束时,不要指定
@ValidCollection
约束的约束
属性。当bean没有约束时,constraints
属性是必需的。感谢becomputer06的精彩回答。
但我认为应在ValidCollection定义中添加以下注释:
@Target( { ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = ValidCollectionValidator.class)
我仍然不知道如何处理基本类型包装器集合和约束注释,如@Size、@Min、@Max等,因为值不能通过becomputer06传递
当然,我可以为应用程序中的所有情况创建自定义约束注释,但无论如何,我必须将这些注释的属性添加到CollectionElementBean中。这似乎是一个很糟糕的解决方案。由于Java注释本身的限制,不可能编写像
@EachElement
这样的通用包装器注释来包装任何约束注释。但是,您可以编写一个通用约束验证器类,该类将每个元素的实际验证委托给现有约束验证器。您必须为每个约束编写一个包装器注释,但只有一个验证器
我已经在(Maven Central中提供)中实现了这种方法。例如:
@EachSize(min = 5, max = 255)
List<String> values;
编辑:已更新库的当前版本。JSR-303能够扩展内置约束的目标类型:请参阅
您可以实现一个
ConstraintValidator
,它执行与给定答案相同的操作,委托给原语验证器。然后,您可以保留您的模型定义,并在列表中应用@Email
我没有足够高的声誉对原始答案进行评论,但也许值得注意的是,这个问题正处于最终发布阶段,将在发布时解决这个问题!然而,它至少需要Java8
唯一的区别是验证注释将放在类型声明中
//@Email
public List<@Email String> getEmailAddresses()
{
return this.emailAddresses;
}
/@电子邮件
公共列表getEmailAddresses()
{
返回此电子邮件地址;
}
请让我知道你认为我最好把这些信息放在哪里,以供其他正在寻找的人使用。谢谢
附:有关更多信息,可以使用非常简单的解决方法。您可以改为验证包装simple value属性的类集合。为此,您需要在集合上使用@Valid
注释
示例:
public class EmailAddress {
@Email
String email;
public EmailAddress(String email){
this.email = email;
}
}
public class Foo {
/* Validation that works */
@Valid
List<EmailAddress> getEmailAddresses(){
return this.emails.stream().map(EmailAddress::new).collect(toList());
}
}
公共类电子邮件地址{
@电子邮件
字符串电子邮件;
公共电子邮件地址(字符串电子邮件){
this.email=电子邮件;
}
}
公开课Foo{
/*有效的验证*/
@有效的
列出getEmailAddresses(){
返回此.emails.stream().map(EmailAddress::new).collect(toList());
}
}
多好的答案啊!我会尽快处理这个问题。谢谢你,becomputer06!非常详细和详细的回答!这看起来太棒了,伙计,可惜打不出来:(。那会让一切变得更美好elegant@Stef看看当前版本。@JakubJirutka我对我的自定义约束做了完全相同的事情,但是我从CommonEachValidator
初始化中得到一个异常,说我正在使用Awesome.class
,本身没有验证器吗?它仅使用@模式
约束,而不使用任何约束else@JakubJirutka是的,对于自定义验证器,我收到了相同的消息。例如,有一个验证集合的伟大框架的示例将非常好。这样一来,人们就可以直接复制……除非我遗漏了你的文档。我想我不是。提前谢谢。@JakubJirutka好的,现在对我有效(我的错误),但我没有收到集合中所有失败条目的错误消息…所以我有点回到原点…换句话说,如果我有一组1个有效值和2个无效值,它会在第一个无效值之后停止验证吗,或者它会验证所有的错误,并返回整个集合的错误,这就是我正在寻找的。提前感谢…这个例子将非常棒…因为我非常确定这是一个常见的用例…无论验证在哪里失败,都可以验证所有内容。有趣的方法。但是,我找不到任何对支持新的TYPE\u USE
注释的验证程序包的引用。我只发现这篇文章提到Hibernate Validator 5.2可能支持它:这是正确的答案,前提是您在方法中添加了@Valid
(而不是注释的/@Email
)链接到文档?以下是
02:16:37,581 INFO main validation.ValidCollectionTest:66 - {ValidCollection.message}
02:16:38,303 INFO main validation.ValidCollectionTest:66 - may not be null
02:16:39,092 INFO main validation.ValidCollectionTest:66 - not a well-formed email address
02:17:46,460 INFO main validation.ValidCollectionTest:81 - may not be empty
02:17:47,064 INFO main validation.ValidCollectionTest:81 - {ValidCollection.message}
@Target( { ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = ValidCollectionValidator.class)
@EachSize(min = 5, max = 255)
List<String> values;
// common boilerplate
@Documented
@Retention(RUNTIME)
@Target({METHOD, FIELD, ANNOTATION_TYPE})
// this is important!
@EachConstraint(validateAs = Awesome.class)
@Constraint(validatedBy = CommonEachValidator.class)
public @interface EachAwesome {
// copy&paste all attributes from Awesome annotation here
String message() default "";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String someAttribute();
}
//@Email
public List<@Email String> getEmailAddresses()
{
return this.emailAddresses;
}
public class EmailAddress {
@Email
String email;
public EmailAddress(String email){
this.email = email;
}
}
public class Foo {
/* Validation that works */
@Valid
List<EmailAddress> getEmailAddresses(){
return this.emails.stream().map(EmailAddress::new).collect(toList());
}
}