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);
}
}