Search code examples
javaspringspring-bootspring-mvcannotations

Spring Validator annotation is not working


In my request body I am passing parameter in different way to validate.

{ 
  "name":[]
}

Here the operation is executing which I want to restrict with my custom error message.

Here I am getting 400 bad request so how to handle this with proper error message.

In my controller I had

if (myRequestResult.getName() == null || myRequestResult.getName().isEmpty()) {
    throw new Exception();
 } else {
    myService.setName(myRequestResult.getName());
 }

Which is working fine but Now I remove that and Using validator annotation.

@Data 
public class MyResultRequest {
  
  @NotEmpty(message = "List of name must not be empty")
  @Size(min = 1, message = "List of name must have at least one element")
  private List<String> name;

}

This is my restcontroller

@Log4j2
@RestController(value = "apiMyController")
@RequestMapping(path = "/api/v1/someRandomeURL")
@RequiredArgsConstructor(onConstructor = @__({@Autowired}))
public class ExecutionResultsController {
  
  @RequestMapping(method = RequestMethod.POST)
  public ExecutionResultDTO create(@RequestBody  MyRequestResult myRequestResult) throws Exception {
     myService.setName(myRequestResult.getName());
  }
}  

Can anybody tell me how to fix that as I am following this from here Doc


Solution

  • @seenukarthi is actually correct. You have to use @Valid on the endpoint to valid the request body.

    Note: The validation errors are not visible in the error response.

    The error will appear in the console log. Example:

    2023-11-20T13:12:13.057+05:30  WARN 85261 --- [nio-8081-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public org.springframework.http.ResponseEntity<java.lang.Object> com.example.TestController.create(com.example.MyRequestResult) with 2 errors: [Field error in object 'myRequestResult' on field 'name': rejected value [[]]; codes [NotEmpty.model.name,NotEmpty.name,NotEmpty.java.util.List,NotEmpty]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [model.name,name]; arguments []; default message [name]]; default message [List of name must not be empty]] [Field error in object 'model' on field 'name': rejected value [[]]; codes [Size.model.name,Size.name,Size.java.util.List,Size]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [model.name,name]; arguments []; default message [name],2147483647,1]; default message [List of name must have at least one element]] ]
    

    Please look into the logs properly. It will be there.


    Now, if you want to capture validation errors happened on request body and to include it to response, then you have to use org.springframework.validation.BindingResult.

    Let me show with an example:

    Update ExecutionResultDTO to have errors list also if possible :

    @Data
    public class ExecutionResultDTO {
    
        private List<String> name;
    
        private List<String> errors;
    
    }
    

    Updated controller that I have used for testing:

    import jakarta.validation.Valid;
    import org.springframework.context.support.DefaultMessageSourceResolvable;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.validation.BindingResult;
    import org.springframework.web.bind.annotation.*;
    
    @RestController
    public class TestController {
    
        @PostMapping("create")
        public ResponseEntity<ExecutionResultDTO> create(@Valid @RequestBody MyRequestResult myRequestResult, BindingResult bindingResult) {
            ExecutionResultDTO dto = new ExecutionResultDTO();
            dto.setName(myRequestResult.getName());
            if (bindingResult.hasErrors()) {
                dto.setErrors(bindingResult.getFieldErrors().stream()
                        .map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.toList()));
                return new ResponseEntity<>(dto, HttpStatus.BAD_REQUEST);
            }
            return new ResponseEntity<>(dto, HttpStatus.CREATED);
        }
    }
    

    Postman :

    For Incorrect Data:

    enter image description here

    For Correct Data:

    enter image description here

    Change the logic accordingly. This is just an example.