Can @Valid be used with @HashMap generated from JSON payload?
I am trying to use spring-mvc @Valid
next to mine @RequestBody
to check if my json payload has a given parameter.
I've found solutions that use binding, but it's almost like calling validation in your method @RequestMapping
. I also found a way to use @Valid
when you have the expected payload.
My payload is fully dynamic and I only want to check if a field exists, eg id
. My current handler:
@RequestMapping(method = RequestMethod.POST, value="/path", consumes = "application/json")
@ResponseBody
@Valid
public Object get(final HttpServletRequest request, @Valid @RequestBody HashMap payload ) {
Since my payload is fully dynamic, I created HashMap
to hold it. I was wondering if I could use @NotEmpty
or a similar annotation if I add HashMap
to a custom class that just checks if the property exists.
Am I on the right track? Is this not possible for dynamic payloads?
Thanks in advance.
source to share
Question: yes and no.
Yes , you can use @Valid
to request verification.
No , you cannot use a simple @NotEmpty
for a property, as you need a specific DTO for this purpose.
Considering the payload is dynamic, the best thing I could do was based on @EddieB 's tutorial link and it goes like this.
Same function header as mine in the question
@RequestMapping(method = RequestMethod.POST, value="/path", consumes = "application/json")
@ResponseBody
public Object get(final HttpServletRequest request, @Valid @RequestBody HashMap payload ) {
But since the payload is dynamic, in this case the HashMap you need some custom validation. The cleanest way I found was to use annotation @InitBinder
to attach Validator
to this request @Valid
.
// instantiated in the constructor
private final MyValidator myValidator
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.setValidator(this.myValidator);
}
And then our custom validator:
public class MyValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return HashMap.class.isAssignableFrom(clazz);
}
@Override
public void validate(Object target, Errors errors) {
// do your custom validation.
// if you don't call error.reject* it is considered a valid argument
}
If you make a mistake, you will catch it by creating a @ControllerAdvice
. In my case, I explicitly set @ResponseStatus
to BAD_REQUEST
, as if it got here, this is definitely caused by a bad payload:
@ControllerAdvice
public class MyHandler{
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public String processValidationError(MethodArgumentNotValidException exception) {
// custom error handling
}
}
Thanks to both members for the comments that led me to this answer.
source to share