Reputation: 1299
I have controller handler like this:
@RequestMapping(method = POST, consumes = MediaType.APPLICATION_JSON_VALUE)
@ApiOperation(value = "Add to basket")
@ApiResponses(value = {@ApiResponse(code = 200, message = "Successfully add to basket")})
@PreAuthorize("@securityService.hasUserAccess()")
public ResponseEntity addToBasket(@RequestBody @ItemAlreadyExistInBasket ProductEntity product) {
basketService.addToBasket(product);
return new ResponseEntity(HttpStatus.OK);
}
The think is that annotation
@ItemAlreadyExistInBasket
is never triggered and I dont know why. This is my annotation with Constraint validation
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = ItemAlreadyExistInBasketConstraint.class)
public @interface ItemAlreadyExistInBasket {
String message() default "Item already exist in basket";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
public class ItemAlreadyExistInBasketConstraint implements ConstraintValidator<ItemAlreadyExistInBasket, ProductEntity> {
@Autowired
private BasketRepository basketRepository;
@Autowired
private UserRepository userRepository;
@Override
public void initialize(ItemAlreadyExistInBasket constraintAnnotation) {
}
@Override
public boolean isValid(ProductEntity productEntity, ConstraintValidatorContext context) {
userRepository.findByLogin(UserUtil.getAuthenticatedUserName());
return basketRepository.findByUserAndStatusAndProduct(userRepository.findByLogin(UserUtil.getAuthenticatedUserName()), Status.ACTIVE, productEntity).isEmpty();
}
}
Any ideas ?
Upvotes: 3
Views: 2317
Reputation: 1691
I also had to deal with these method validations recently, don't know if you already found the answer for this problem but I am still going to answer it. The following works with Spring 4.1.2 (possibly earlier versions also)
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
@RestController
@Validated
[...]
public class YourController ...
Just like you posted in your question, you may implement validators using the JSR303 spec.
Somehow, Spring deals with the validation errors differently when using @Value and method validation. So if you want your method to return a 400 error instead of throwing a server exception, you also need to implement something similar to this method:
/**
* Handle Constraint exceptions in order to return a bad request http status
*/
@ExceptionHandler(value = { ConstraintViolationException.class })
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public String handleResourceNotFoundException(ConstraintViolationException e) {
Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
StringBuilder strBuilder = new StringBuilder();
for (ConstraintViolation<?> violation : violations ) {
strBuilder.append(violation.getMessage() + "\n");
}
return strBuilder.toString();
}
Strangely, I had to place this method in my RestController. I did test implementing it inside a @Configuration class, but it didn't work.
If you want both POJO validation and method parameter validation, use both @Validated annotation on class level and @Valid before a POJO on the method. When using @Valid annotation, everything declared inside this POJO (for instance @NotNull on a field) will be also validated. This was the use case I had to implement.
Hope this helps!
Upvotes: 6