How to validate Spring MVC @PathVariable values?

Spring does not support @javax.validation.Valid on @PathVariable annotated parameters in handler methods. There was an Improvement request, but it is still unresolved.

Your best bet is to just do your custom validation in the handler method body or consider using org.springframework.validation.annotation.Validated as suggested in other answers.


You can use like this: use org.springframework.validation.annotation.Validated to valid RequestParam or PathVariable.

 *
 * Variant of JSR-303's {@link javax.validation.Valid}, supporting the
 * specification of validation groups. Designed for convenient use with
 * Spring's JSR-303 support but not JSR-303 specific.
 *

step.1 init ValidationConfig

@Configuration
public class ValidationConfig {
    @Bean
    public MethodValidationPostProcessor methodValidationPostProcessor() {
        MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
        return processor;
    }
}

step.2 Add @Validated to your controller handler class, Like:

@RequestMapping(value = "poo/foo")
@Validated
public class FooController {
...
}

step.3 Add validators to your handler method:

   @RequestMapping(value = "{id}", method = RequestMethod.DELETE)
   public ResponseEntity<Foo> delete(
           @PathVariable("id") @Size(min = 1) @CustomerValidator int id) throws RestException {
        // do something
        return new ResponseEntity(HttpStatus.OK);
    }

final step. Add exception resolver to your context:

@Component
public class BindExceptionResolver implements HandlerExceptionResolver {

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        if (ex.getClass().equals(BindException.class)) {
            BindException exception = (BindException) ex;

            List<FieldError> fieldErrors = exception.getFieldErrors();
            return new ModelAndView(new MappingJackson2JsonView(), buildErrorModel(request, response, fieldErrors));
        }
    }
}

The solution is simple:

@GetMapping(value = {"/", "/{hash:[a-fA-F0-9]{40}}"})
public String request(@PathVariable(value = "hash", required = false) String historyHash)
{
    // Accepted requests: either "/" or "/{40 character long hash}"
}

And yes, PathVariables are ment to be validated, like any user input.


Instead of using @PathVariable, you can take advantage of Spring MVC ability to map path variables into a bean:

@RestController
@RequestMapping("/user")
public class UserController {

    @GetMapping("/{id}")
    public void get(@Valid GetDto dto) {
        // dto.getId() is the path variable
    }

}

And the bean contains the actual validation rules:

@Data
public class GetDto {
     @Min(1) @Max(99)
     private long id;
}

Make sure that your path variables ({id}) correspond to the bean fields (id);