What is the difference between ConstraintViolationException and MethodArgumentNotValidException
Asked Answered
A

3

28

When I am validating bean using @Valid annotation in javax.validation, for some objects I am getting ConstraintViolationException and for some I am getting a MethodArgumentNotValidException.

I understand that, if I validate anything in @ResponseBody in the controller , it throws a MethodArgumentNotValidException.

But for some custom validations(eg. @MyCustomValidation) at the class level it is throwing ConstraintViolationException even if it is being validated in @ResponseValidation.

And for some other custom validation for a different REST endpoint, it throws MethodArgumentNotValidException.

I am finding it a bit difficult to understand its behavior.

@PostMapping(path = "/someEndPoint")    
@Validated(OnASave.class)
public ResponseEntity<ClassA> saveObjA(@Valid @RequestBody ClassA objA)

Result - throws MethodArgumentNotValidException

@PostMapping(path = "/someOtherEndPoint")   
@Validated(OnBSave.class)
public ResponseEntity<ClassB> saveObjB(@Valid @RequestBody ClassB objB)

Result - throws ConstraintViolationException

Both ClassA and ClassB has custom validations.

Adelaadelaida answered 12/7, 2019 at 16:18 Comment(9)
can you add the stack trace or fully qualified name of both exceptionsAlgophobia
I checked the root cause in debug mode but it is showing all validated fields in the root cause and the exception is sameAdelaadelaida
why don't you add it hereAlgophobia
and also add the ClassA and ClassB with import statements, there is a possibility of ConstraintViolationException which is part of jsr 380Algophobia
Exception strace for : javax.validation.ConstraintViolationException: methodName.obj_name.field_name: must not be blankAdelaadelaida
Import statements are :Adelaadelaida
import javax.validation.Valid; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.Pattern; import javax.validation.constraints.Size;Adelaadelaida
I can not post completed code hereAdelaadelaida
@Deadpool : One thing I observed is whenever I add validation groups (eg. @SomeValidation(groups=GroupA.class)) I get ConstraintViolationException and If I remove groups I get MethodArgumentNotValidExceptionAdelaadelaida
P
17

For a simple understanding, if validation happens at the controller/service layer by using the @Valid annotation, it generates MethodArgumentNotValidException. You can add a handler for this and return the response accordingly. This class is part of the Spring framework, and validation is performed by the Spring framework. See sample below:

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Response> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
    
        logger.info("Invalid arguments found : " + ex.getMessage());
        // Get the error messages for invalid fields
        List<FieldError> errors = ex.getBindingResult()
                .getFieldErrors()
                .stream()
                .map(fieldError -> new FieldError(fieldError.getField(), fieldError.getDefaultMessage()))
                .collect(Collectors.toList());
    
        String message = messageSource.getMessage("invalid.data.message", null, LocaleContextHolder.getLocale());
        Response response = new Response(false, message)
                .setErrors(errors);
        ResponseEntity<Response> responseEntity = ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
        return responseEntity;
    }

Instead, if you do not validate using the @Valid annotation, an exception is raised by Hibernate at the JPA layer and generates ConstraintViolationException. This exception is part of the Javax bean validation framework and raised at the time of performing the persistence operation (before the actual SQL execution). See sample below:

    @ExceptionHandler(ConstraintViolationException.class)
        public ResponseEntity<Response> handleConstraintViolationException(ConstraintViolationException ex) {
            List<FieldError> errors = ex.getConstraintViolations()
                    .stream()
                    .map(constraintViolation -> {
                        return new FieldError(constraintViolation.getRootBeanClass().getName() + " " + constraintViolation.getPropertyPath(), constraintViolation.getMessage());
                    })
                    .collect(Collectors.toList());
    
            String message = messageSource.getMessage("invalid.data.message", null, LocaleContextHolder.getLocale());
            Response response = new Response(false, message)
                    .setErrors(errors);
            ResponseEntity<Response> responseEntity = ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
            return responseEntity;
        }
Probative answered 5/6, 2021 at 11:48 Comment(0)
C
12

When you use @Valid, you are applying validation which is defined by you on your model class fields, while there are different types of validations, you can choose like @NotNull, @Max, @Min and so on, you will get the matching type.

In general, all of these are parallel to MethodArgumentNotValidException which will be thrown in all cases.

From official document

Exception to be thrown when validation on an argument annotated with @Valid fails.

ConstraintViolationException is thrown by hibernate entity manager when some constrain violated, so this means you violated some fields in some entity you are using.

Cosgrove answered 12/7, 2019 at 16:28 Comment(2)
Thank you very much for your quick reply. Even I was under the same assumption but the strange thing is when I move all the validations to service layer, it always throws ConstraintViolationException for all the validations. Not even a single validation throws MethodArgumentNotValidExceptionAdelaadelaida
As I mentioned in the answer this is thrown from some JPA provider which you are using, Iyou can check that via debugging to see which field exactly is the reason of this? or you can share the code of your model class to see togetherCosgrove
P
6

Take a look at this article. These exceptions are thrown under different situations when you mix spring's validation framework with bean validation.

Pierson answered 19/10, 2020 at 20:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.