How to: Spring get rid of @Validate for automatic Controller validation?

后端 未结 3 1602
自闭症患者
自闭症患者 2021-02-09 13:39

I know about @Valid annotation to instruct spring to validate for example a Controller argument according to JSR-303 in such this example:

@GetMappi         


        
相关标签:
3条回答
  • 2021-02-09 14:05

    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);
        }
    
    }
    
    0 讨论(0)
  • 2021-02-09 14:15

    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.

    0 讨论(0)
  • 2021-02-09 14:18

    It should be possible to do this however like Markus in the similar question I'm not sure I agree its solving an actual problem.

    Without getting too far into the weeds, Spring performs validation as part of model binding within ModelAttributeMethodProcessor's validateIfApplicable method. Per the javadoc

    Validate the model attribute if applicable. The default implementation checks for @javax.validation.Valid, Spring's Validated, and custom annotations whose name starts with "Valid".

    To override this functionality you need to create a custom ModelAttributeMethodProcessor / ServletModelAttributeMethodProcessor. You then would need to register it as an argument resolver

    public class ApplicationConfiguration extends WebMvcConfigurerAdapter {
        @Override
        public void addArgumentResolvers(final List<HandlerMethodArgumentResolver> argumentResolvers) {
            // add your custom model attribute processor here
        }
    }
    
    0 讨论(0)
提交回复
热议问题