Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Controller: RequestParam not validated despite @Valid and @Size

I have a simple Controller method :

@GetMapping("/search")
    public List<Result> search(@RequestParam @Valid @NotNull @Size(min = 4) String query) {
        return searchService.search(query);
    }

When I omit the "query" parameter, I get a 400 Bad Request, as expected.

Testing the method with these query parameters doesn't work.

All but the last test should return a "400 Bad Request".

"/search"             --> actual 400 Bad Request, test passes
"/search?query="      --> actual 200 Ok, expected 400 because @Size(min=4)
"/search?query=a"     --> actual 200 Ok, expected 400 because @Size(min=4)
"/search?query=ab"    --> actual 200 Ok, expected 400 because @Size(min=4)
"/search?query=abc"   --> actual 200 Ok, expected 400 because @Size(min=4)
"/search?query=abcd"  --> actual 200 Ok, test passes

Why is the @Size(min=4) annotation being ignored?

like image 679
Wolf359 Avatar asked Jan 28 '23 01:01

Wolf359


2 Answers

Validating RequestParameters does not work like that out of the box.

You could wrap the parameters in a class like

class SearchRequest {
    @Size(min=4)
    @NotNull
    private String query;
    ...
}

Then change your controller code to

@GetMapping("/search")
public List<Result> search(@ModelAttribute @Valid SearchRequest searchRequest) {
    return searchService.search(searchRequest.getQuery());
}

Now this is one way to do it, what you want is probably achievable using the @Validated annotation on the class, but I don't know anything about that but it seems to be covered here: https://sdqali.in/blog/2015/12/04/validating-requestparams-and-pathvariables-in-spring-mvc/

like image 90
Mico Avatar answered Jan 29 '23 14:01

Mico


You can use RequestParameters validation out of the box)

You need to add MethodValidationPostProcessor to your configuration

@org.springframework.context.annotation.Configuration
public class Configuration {

    @Bean
    public MethodValidationPostProcessor methodValidationPostProcessor() {
        return new MethodValidationPostProcessor();
    }

}

And @Validated Annotation to your controller

@RestController
@Validated
public class MyController {

    @GetMapping("/search")
    public String search(@RequestParam @NotNull @Size(min = 4) String query) {
        return "success";
    }

}

Remember also, that you may want to handle exception, which is thrown if method parameters not valid, you may do it like this

@ControllerAdvice
@Component
public class ExceptionHandler {
    @ExceptionHandler
    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public List handle(MethodArgumentNotValidException exception) {
        //do your stuff here
        return exception.getBindingResult().getFieldErrors()
                .stream()
                .map(FieldError::getDefaultMessage)
                .collect(Collectors.toList()));
    }


    @ExceptionHandler
    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public List handle(ConstraintViolationException exception) {
       //do your staff here
    }

}
like image 42
Alex G. Avatar answered Jan 29 '23 14:01

Alex G.