javaspring-bootspring-boot-starter

getting ConstraintViolationException instead of MethodArgumentNotValidException when using @valid with @RequestBody in the controller


i am continuing my journey to learn Spring boot, right now i am stuck between two similar kind of exceptions, wherever i found i have got the answer that if @valid or @validate used at controller/service level along with @RequestBody we should get MethodArgumentNotValidException whereas, i am getting ConstraintViolationException during post and update API calls. again and again the call is going in globalExceptionHandler method of ExceptionHAndler class, where it is showing constraintviolationexception.

PostController.java

@RestController
@RequestMapping("/api/posts")
public class PostController {
    
    @Autowired
    private PostService postService;

    //rest API endpoint to post http:localhost:8080/api/posts
    @PostMapping
    public ResponseEntity<PostDTO> createPost(@Valid @RequestBody PostDTO postDTO){
        return new ResponseEntity<>(postService.createPost(postDTO),HttpStatus.CREATED);
    }
    
    @PostMapping(path = "/multiple")
    public ResponseEntity<List<PostDTO>> createMultiplePosts(@Valid @RequestBody List<PostDTO> postDTO){
        
        return new ResponseEntity<>(postService.createMultiplePosts(postDTO),HttpStatus.CREATED);
    }

Entity Class:

Posts.java

@Entity
@Table(name = "posts", uniqueConstraints = {@UniqueConstraint(columnNames = {"titles"})})
public class Posts {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;
    @Column(name = "titles")
    @NotEmpty
    @Size(min = 2,message = "post title should contain atleast 2 character")
    private String title;
    @Column(name = "description")
    @NotEmpty
    @Size(min = 10,message = "post description should contain atleast 2 character")
    private String description;
    @Column(name = "content")
    @NotEmpty
    private String content;

GlobalException.java

@ControllerAdvice
public class GlobalException extends ResponseEntityExceptionHandler {
    
    private static final Logger logger = LoggerFactory.getLogger(GlobalException.class);
    
    @ExceptionHandler(ResouceNotFoundException.class)
    ResponseEntity<ErrorDetails> PostNotFoundExceptionHandler(ResouceNotFoundException exception, WebRequest webRequest){
        
        ErrorDetails errorDetails =new ErrorDetails(new Date(),exception.getMessage(),webRequest.getDescription(false));
        return new ResponseEntity<>(errorDetails,HttpStatus.NOT_FOUND);
    }
    
    @ExceptionHandler(BlogApiException.class)
    ResponseEntity<ErrorDetails> CommentNotFoundExceptionHandler(BlogApiException exception, WebRequest webRequest){
        
        ErrorDetails errorDetails =new ErrorDetails(new Date(),exception.getMessage(),webRequest.getDescription(false));
        return new ResponseEntity<>(errorDetails,HttpStatus.NOT_FOUND);
    }
    
    
    @Override
//  @ExceptionHandler(MethodArgumentNotValidException.class)
    protected ResponseEntity<Object> handleMethodArgumentNotValid(
            MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request){
        
        logger.info("inside handleMethodArgumentNotValid class");
        Map<String, String> errorsMap =new HashMap<>();
        ex.getBindingResult().getAllErrors().forEach((error)->{
        
            String fieldNameString = ((FieldError)error).getField();
            String messageString = error.getDefaultMessage();
            errorsMap.put(fieldNameString, messageString);
        });
        return new ResponseEntity<>(errorsMap,HttpStatus.BAD_REQUEST);
    }
    
    @ExceptionHandler(Exception.class)
    ResponseEntity<ErrorDetails> GlobalExceptionHandler(Exception exception, WebRequest webRequest){
        logger.info("inside GlobalExceptionHandler class");
        ErrorDetails errorDetails =new ErrorDetails(new Date(),exception.getMessage(),webRequest.getDescription(false));
        return new ResponseEntity<>(errorDetails,HttpStatus.BAD_REQUEST);
    }

}

i tried modifying RequestBody JSON, tried @validated annotation at class level, and at method level after @RequestBody annotation as well, still getting same exception. please help me to understand why am I getting this exception, tried playing with versions of spring boot starter validation dependency. currently using 3.0.4 version of starter-validation dependency Java version is 17.0.7


Solution

  • Why do you think you should get MethodArgumentNotValidException? ConstraintViolationException seems to be totally reasonable exception to expect, when some constraints were violated by your request body. I don't see a problem here. Just change your ExceptionHandler to catch ConstraintViolationException and do whatever you want with it.