扩展Hibernate Validator约束的问题

时间:2015-02-02 23:24:07

标签: java hibernate

我正在尝试通过创建名为URI的自定义约束来扩展@NotBlank constraint的行为以应用于@NotBlankUri

这是我的约束注释:

@Target({ METHOD, FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = NotBlankUriValidator.class)
public @interface NotBlankUri {
    String message() default "{project.model.NotBlankUri.message}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

这是ConstraintValidator

public class NotBlankUriValidator implements ConstraintValidator<NotBlankUri, URI> {

    public void initialize(NotBlankUri annotation) {
    }

    public boolean isValid(URI uri, ConstraintValidatorContext context) {
        NotBlankValidator nbv = new NotBlankValidator();
        return nbv.isValid(uri.toString(), context);
    }
}

问题是isValid()上的ConstraintValidator方法获得了null参数的URI值。我认为这不应该发生,因为@NotBlank本身is annotated @NotNull。不是这样,我尝试将@NotNull添加为我的@NotBlankUri的元注释,但这也没有达到预期的效果。如何使我的注释约束表现得像@NotBlank,它似乎堆叠在@NotNull的行为之上?

1 个答案:

答案 0 :(得分:1)

根据文档,您不能对不是String的数据类型使用@NotBlank注释。

  

public @interface NotBlank

     

验证带注释的字符串不为null或为空。与NotEmpty的区别在于尾随空格被忽略。

因此,如果您声明验证器验证字符串,一切都会好的,您可以像这样编写注释:

@Target({ METHOD, FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = NotBlankUriValidator.class)
@NotBlank    
public @interface NotBlankUri {
    String message() default "{project.model.NotBlankUri.message}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

如果您对使用URI类 1 不熟悉,则需要自己执行自定义验证逻辑:

注释:

@NotNull(message="URI must not be null")
@Target({ METHOD, FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = NotBlankUriValidator.class)
public @interface NotBlankUri {
    String message() default "URI must not be blank";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

验证

public class NotBlankUriValidator implements ConstraintValidator<NotBlankUri, URI> {
    public void initialize(NotBlankUri annotation) {
    }

    public boolean isValid(URI uri, ConstraintValidatorContext context) {
        boolean isValid = true;
        System.out.println("URI: " + uri);
        //Leave null checks to your @NotNull constraint.
        //This is only here to prevent a NullPointerException on the next check.
        if(uri == null){
            return true;
        }
        if(uri.toString().isEmpty()){
            isValid = false;
        }
        return isValid;
    }
}

我使用测试工具运行上述内容:

public class UriContainer {

    public UriContainer(URI uri){
        this.uri = uri;
    }
    @NotBlankUri
    private URI uri;

    public URI getUri() {
        return uri;
    }
}

public static void main(String[] args) throws URISyntaxException{
    UriContainer filledContainer = new UriContainer(new URI("Stuff"));
    UriContainer emptyContainer = new UriContainer(new URI(""));
    UriContainer nullContainer = new UriContainer(null);

    Validator validator = Validation.buildDefaultValidatorFactory().getValidator();

    Set<ConstraintViolation<UriContainer>> filledViolations = validator
            .validate(filledContainer);

    Set<ConstraintViolation<UriContainer>> emptyViolations = validator
            .validate(emptyContainer);

    Set<ConstraintViolation<UriContainer>> nullViolations = validator
            .validate(nullContainer);

    System.out.println("Filled: ");
    filledViolations.stream().forEach(System.out::println);
    System.out.println("Empty: ");
    emptyViolations.stream().forEach(System.out::println);
    System.out.println("Null: ");
    nullViolations.stream().forEach(System.out::println);

}

输出以下违规行为:

  

URI:东西
  URI:
  URI:null
  填写:
  空:
  ConstraintViolationImpl {interpolatedMessage ='URI不能为空',propertyPath = uri,rootBeanClass = class sandbox.UriContainer,messageTemplate ='URI不能为空'}
  空:
  ConstraintViolationImpl {interpolatedMessage ='URI不能为null',propertyPath = uri,rootBeanClass = class sandbox.UriContainer,messageTemplate ='URI不能为null'}

如您所见,这允许您根据URI是空白还是空来输出不同的错误消息。只需确保使用javax.validation注释,检查您操作的数据类型。

1:顺便说一句,在构造对象时执行验证,如果传递给构造函数的String违反RFC 2396

,则抛出URISyntaxException