I know about @Valid annotation to instruct spring to validate for example a Controller argument according to JSR-303 in such this example:
@GetMapping("/test")
public TestDTO testDTO(@Valid TestDTO testDTO){
return testDTO;
}
But I would like to be able to configure Spring in some way to enable validation in all my controllers without specify explicitly the @Valid annotation.
Is that possible in any way? Some Spring configuration? Making use of AOP?...
I have finally came across with a working solution which may be not the optimal from the point of view of Spring configuration (as I said I'm Spring beginner).
The idea was to modify the argument resolvers (the ones that implement HandlerMethodArgumentResolver), replacing the argument resolver associated to arguments with a @RequestBody annotation. Creating an inherited class from the default one (which is RequestResponseBodyMethodProcessor) and overriding a method in the class hierarchy which efectively determines if perform a validation or not (based in the presence of @Valid, @Validated, @ValidXxxxxx annotations as the default behaviour), making to always validate with no further check.
So here is the code (I'm using Java 8 BTW):
Extend RequestResponseBodyMethodProcessor to define validation strategy (in this case, always validate):
public class MyRequestResponseBodyMethodProcessor extends RequestResponseBodyMethodProcessor {
public MyRequestResponseBodyMethodProcessor(List<HttpMessageConverter<?>> converters) {
super(converters);
}
@Override
protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {
binder.validate(); // always validating @RequestMapping annotated parameters ;)
}
}
Define a @Configuration class where to replace default argument resolver:
@Configuration
public class MyValidationAdapterConfigurer {
@Autowired
private RequestMappingHandlerAdapter requestMappingHandlerAdapter;
// Injecting your own resolver
@Autowired
private RequestResponseBodyMethodProcessor requestResponseBodyMethodProcessor;
@PostConstruct
public void init() {
// Don't know why but, removing the target resolver and adding the injected one to the end does not work!
// Must be something related with the resolvers ordering. So just replacing the target in the same position.
final List<HandlerMethodArgumentResolver> mangledResolvers = requestMappingHandlerAdapter.getArgumentResolvers().stream()
.map(resolver -> resolver.getClass().equals(RequestResponseBodyMethodProcessor.class) ?
requestResponseBodyMethodProcessor: resolver)
.collect(Collectors.toList());
requestMappingHandlerAdapter.setArgumentResolvers(mangledResolvers);
}
}
Finally configure Spring to deliver your customized Bean in your Application configuration class:
@Configuration
@PropertySource("classpath:api.properties")
public class MyRestApiConfiguration {
@Bean
@Autowired
RequestResponseBodyMethodProcessor requestResponseBodyMethodProcessor(List<HttpMessageConverter<?>> converters) {
return new MyRequestResponseBodyMethodProcessor(converters);
}
}
unfortunately there is no "legal" way to do it.
Furthermore @Valid is not enough. You need also a BindingResult method parameter to be able to check the validation result: bindingResult.hasErrors()
If you don't want to use BindingResult, you could write your own Validator and throw an Exception in case of invalid input.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With