2012-07-09 35 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