2012-07-09 76 views
4

定制Hibernate验证我想创建一个基于Hibernate的@Length约束定制约束@LengthIfNotBlank(min=,max=)创建基于现有的Hibernate验证

@Target({ METHOD, FIELD, ANNOTATION_TYPE }) 
@Retention(RUNTIME) 
@Constraint(validatedBy = LengthIfNotBlankValidator.class) 
@Documented 
public @interface LengthIfNotBlank { 
    String message() default "{com.mycompany.LengthIfNotBlank}"; 
    Class<? extends Payload>[] payload() default {}; 
    int max() default Integer.MAX_VALUE; 
    Class<?>[] groups() default {}; 
    int min() default 0; 
} 

public class LengthIfNotBlankValidator extends LengthValidator { 
    @Override 
    public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) { 
     return StringUtils.isBlank(value) || super.isValid(value, constraintValidatorContext); 
    } 
} 

例外:

[java] javax.validation.ValidationException: Unable to initialize com.example.constraints.LengthIfNotBlankValidator 
[java] Caused by: java.lang.ClassCastException: $Proxy32 cannot be cast to org.hibernate.validator.constraints.Length 

UPDATE

仍然得到这个例外:-(

public class LengthIfNotBlankValidator extends LengthValidator { 
    public void initialize(LengthIfNotBlank parameters) { 
     Map<String,Object> elements = new HashMap<String,Object>(); 
     elements.put("message", parameters.message()); 
     elements.put("payload", parameters.payload()); 
     elements.put("groups", parameters.groups()); 
     elements.put("min", parameters.min()); 
     elements.put("max", parameters.max()); 

     AnnotationDescriptor<Length> descriptor = AnnotationDescriptor.getInstance(Length.class, elements); 
     Length length = AnnotationFactory.create(descriptor); 
     super.initialize(length); 
    } 

    @Override 
    public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) { 
     return StringUtils.isBlank(value) || super.isValid(value, constraintValidatorContext); 
    } 
} 

回答

2

由于注释类型不能被继承,你应该重写initialize()并通过Length类型的实际实例super.initialize()

请注意,您不能直接创建注释类型的实例,因此您必须使用类似AnnotationFactory之类的内容。

而且我不知道,编译器将允许你这样做,由于类型安全限制。如果没有,使用的组合物,而不是继承的(即创建LengthValidator类型的字段)。

+0

似乎没有按”牛逼的帮助(见上更新部分) – dtrunk 2012-07-09 08:21:16

0

我想你不应该打扰:Hibernate的LengthValidator是非常简单的,并不管你做什么,你最终会与更多的代码,如果你刚刚自己重新实现了这样的代码:

public class LengthIfNotBlankValidator implements ConstraintValidator<LengthIfNotBlank, String> { 
    private int min; 
    private int max; 

    public void initialize(LengthIfNotBlank parameters) { 
     min = parameters.min(); 
     max = parameters.max(); 
     validateParameters(); 
    } 

    public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) { 
     if (StringUtils.isBlank(value)) { 
      return true; 
     } 
     int length = value.length(); 
     return length >= min && length <= max; 
    } 

    private void validateParameters() { 
     if (min < 0) { 
      throw new IllegalArgumentException("The min parameter cannot be negative."); 
     } 
     if (max < 0) { 
      throw new IllegalArgumentException("The max parameter cannot be negative."); 
     } 
     if (max < min) { 
      throw new IllegalArgumentException("The max cannot be less than the min."); 
     } 
    } 
} 

(这只是适合您的特定情况的Hibernate代码)。

另外,我认为在执行ConstraintValidator<LengthIfNotBlank, String>时,我们不可能扩展LengthValidator,这对验证器是必需的。

注意然而,如果你想重新使用unparameterized验证(或恒定的参数验证),你可以简单地用注释您验证重复使用的一个(也许添加@ReportAsSingleViolation

+0

谢谢,但我不喜欢冗余代码。 – dtrunk 2012-07-09 10:10:04

+0

我同意,但我不知道使用反射来避免它真的是好当重复的代码是如此简单。反射代码可能更难理解和维护... – 2012-07-09 14:08:12