I want to register a custom HandlerMethodArgumentResolver
that could handle the following @Controller
handler method definition
@RequestMapping(method = RequestMethod.POST)
public String createDomain(@Valid Domain domain, BindingResult errors, @RequestParam("countryId") Long countryId) {
I can register my resolver, which just creates a Domain
object through request parameters, by overriding addArgumentResolver()
from WebMvcConfigurerAdapter
. When Spring tries to resolve the Domain
parameter, it goes through its list of HandlerMethodArgumentResolver
(there are a lot) and picks the first one that supports()
it.
In the above example, although my resolver will get called and my Domain
argument will get initialized, the @Valid
annotation won't have been processed and the resolver for BindingResult
, an ErrorsMethodArgumentResolver
will fail because it requires a @ModelAttribute
, @RequestBody
or the @RequestPart
argument in the handler method, which I don't have.
If I try to fix it by adding @ModelAttribute
@RequestMapping(method = RequestMethod.POST)
public String createDomain(@Valid @ModelAttribute Domain domain, BindingResult errors, @RequestParam("countryId") Long countryId) {
a HandlerMethodArgumentResolver
implementation, ModelAttributeMethodProcessor
, will get checked first with supports()
and resolve the argument (with @ModelAttribute
and @Valid
) before my custom resolver. The BindingResult
won't fail, but I won't have my custom creation behavior on the Domain
instance.
I could just copy-paste the code for validation and adding to model that's in ModelAttributeMethodProcessor
, but I was hoping there was an easier way to resolve my parameters and perform validation without adding an object to the model. Is there such a way?
Nice description of the issue that you are facing.
I checked out the code that you have outlined and have come to the same conclusion that you have - there is no built-in way to have both a custom HandlerMethodArgumentResolver
as well as @Valid
related validation applied at the same time, the only choice is to do what the ModelAttributeMethodProcessor
does which is to check if the parameter has a @Valid
annotation and call the validation logic related code.
You can probably derive your HandlerMethodResolverArgumentResolver
from ModelAttributeMethodProcessor
and call super.validateIfApplicable(..)
atleast this way the existing code is leveraged.
It's may be too late, but your HandlerMethodArgumentResolver
gets WebDataBinderFactory
object as last argument, then, to hook up the validation, simply add this to your resolver implementation:
Object resolvedObject = // your logic
if(parameter.hasParameterAnnotation(Valid.class){
binderFactory.createBinder(webRequest,resolvedObject,"resolvedObjectLogicalName").validate ();
}
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