Annotations from javax.validation.constraints not working

血红的双手。 提交于 2019-11-27 00:36:57

For JSR-303 bean validation to work in Spring, you need several things:

  1. MVC namespace configuration for annotations: <mvc:annotation-driven />
  2. The JSR-303 spec JAR: validation-api-1.0.0.GA.jar (looks like you already have that)
  3. An implementation of the spec, such as Hibernate Validation, which appears to be the most commonly used example: hibernate-validator-4.1.0.Final.jar
  4. In the bean to be validated, validation annotations, either from the spec JAR or from the implementation JAR (which you have already done)
  5. In the handler you want to validate, annotate the object you want to validate with @Valid, and then include a BindingResult in the method signature to capture errors.

Example:

@RequestMapping("handler.do")
public String myHandler(@Valid @ModelAttribute("form") SomeFormBean myForm, BindingResult result, Model model) {
    if(result.hasErrors()) {
      ...your error handling...
    } else {
      ...your non-error handling....
    }
}

You should use Validator to check whether you class is valid.

Person person = ....;
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();
Set<ConstraintViolation<Person>> violations = validator.validate(person);

Then, iterating violations set, you can find violations.

You would have to call a Validator on the Entity if you want to validate it. Then you will get a set of ConstraintViolationException, which basically show for which field/s of your Entity there is a constraint violation and what exactly was it. Maybe you can also share some of the code you expect to validate your entity.

An often used technique is to do validation in @PrePersist and rollback transaction if using multiple data modifications during transaction or do other actions when you get a validation exception.

Your code should go like this:

@PrePersist
public void prePersist(SomeEntity someEntity){
    Validator validator = Validation.buildDefaultValidatorFactory.getValidator();
    Set<ConstraintViolation<SomeEntity>> = validator.validate(someEntity);
    //do stuff with them, like notify client what was the wrong field, log them, or, if empty, be happy
}

You can also simply use @NonNull with the lombok library instead, at least for the @NotNull scenario. More details: https://projectlombok.org/api/lombok/NonNull.html

in my case i had a custom class-level constraint that was not being called.

@CustomValidation // not called
public class MyClass {
    @Lob
    @Column(nullable = false)
    private String name;
}

as soon as i added a field-level constraint to my class, either custom or standard, the class-level constraint started working.

@CustomValidation // now it works. super.
public class MyClass {
    @Lob
    @Column(nullable = false)
    @NotBlank // adding this made @CustomValidation start working
    private String name;
}

seems like buggy behavior to me but easy enough to work around i guess

I come here some years after, and I could fix it thanks to atrain's comment above. In my case, I was missing @Valid in the API that receives the Object (a POJO in my case) that was annotated with @Size. It solved the issue.

I did not need to add any extra annotation, such as @Valid or @NotBlank to the variable annotated with @Size, just that constraint in the variable and what I mentioned in the API...

Pojo Class:

...
@Size(min = MIN_LENGTH, max = MAX_LENGTH);
private String exampleVar;
...

API Class:

...
public void exampleApiCall(@RequestBody @Valid PojoObject pojoObject){
  ...
}

Thanks and cheers

You need to add @Valid to each member variable, which was also an object that contained validation constraints.

So @Valid at service interface would work for only that object. If you have any more validations within the hierarchy of ServiceRequest object then you might to have explicitly trigger validations. So this is how I have done it:

public class ServiceRequestValidator {

      private static Validator validator;

      @PostConstruct
      public void init(){
         validator = Validation.buildDefaultValidatorFactory().getValidator();
      }

      public static <T> void validate(T t){
        Set<ConstraintViolation<T>> errors = validator.validate(t);
        if(CollectionUtils.isNotEmpty(errors)){
          throw new ConstraintViolationException(errors);
        }
     }

}

You need to have following annotations at the object level if you want to trigger validation for that object.

@Valid
@NotNull

for method parameters you can use Objects.requireNonNull() like this: test(String str) { Objects.requireNonNull(str); } But this is only checked at runtime and throws an NPE if null. It is like a preconditions check. But that might be what you are looking for.

Great answer from atrain, but maybe better solution to catch exceptions is to utilize own HandlerExceptionResolver and catch

@Override
public ModelAndView resolveException(
    HttpServletRequest aReq, 
    HttpServletResponse aRes,
    Object aHandler, 
    Exception anExc
){
    // ....
    if(anExc instanceof MethodArgumentNotValidException) // do your handle     error here
}

Then you're able to keep your handler as clean as possible. You don't need BindingResult, Model and SomeFormBean in myHandlerMethod anymore.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!