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

I know about annotation @Valid

to give spring command to check for example controller argument according to JSR-303 in this example:

@GetMapping("/test")
public TestDTO testDTO(@Valid TestDTO testDTO){
        return testDTO;
}

      

But I would like to be able to customize spring in some way to enable validation in all my controllers without explicitly specifying the annotation @Valid

.

Is this possible anyway? Some spring configuration? Using AOP? ...

+3


source to share


3 answers


I finally came across a working solution that might not be optimal in terms of Spring configuration (since I said I am a Spring newbie).

The idea was to change the arguments arguments (the ones that implement HandlerMethodArgumentResolver

) by replacing the argument argument associated with the arguments with annotation @RequestBody

. Creating a legacy default class ( RequestResponseBodyMethodProcessor

) and override the method in the class hierarchy, which effectively determines whether to perform validation or not (based on the presence @Valid

, @Validated

, @ValidXxxxxx

annotation as the default behavior), allowing you to always check with no further verification.

So here's the code (I'm using Java 8 BTW):

Expand RequestResponseBodyMethodProcessor

to define a validation strategy (in this case, always check):

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 the class @Configuration

where to replace the default argument recognizer:

@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 provide a customized Bean in your application config class:

@Configuration
@PropertySource("classpath:api.properties")
public class MyRestApiConfiguration {

    @Bean
    @Autowired
    RequestResponseBodyMethodProcessor requestResponseBodyMethodProcessor(List<HttpMessageConverter<?>> converters) {
        return new MyRequestResponseBodyMethodProcessor(converters);
    }

}

      

+2


source


Unfortunately, there is no "legal" way to do this.

It is also @Valid

not enough. You also need a method parameter BindingResult

to check the result of the check:bindingResult.hasErrors()



If you don't want to use BindingResult

, you can write your own validator and throw an exception in case of invalid input.

+1


source


This should be possible, however, like Markus in a similar question , I'm not sure if I agree that he solves the real problem.

Without getting too far into the weeds, Spring does validation as part of the model binding in the ModelAttributeMethodProcessor method validateIfApplicable. Per javadoc

Validate the model attribute, if applicable. The default implementation checks for @ javax.validation.Valid, Spring Checked and executed annotations starting with "Valid".

To override this functionality, you need to create your own ModelAttributeMethodProcessor / ServletModelAttributeMethodProcessor. Then you will need to register it as a resolver argument

public class ApplicationConfiguration extends WebMvcConfigurerAdapter {
    @Override
    public void addArgumentResolvers(final List<HandlerMethodArgumentResolver> argumentResolvers) {
        // add your custom model attribute processor here
    }
}

      

0


source







All Articles