-
Notifications
You must be signed in to change notification settings - Fork 38.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve method validation support for containers with constraints on container elements #31887
Comments
Thanks for the feedback and demo. In Spring Validation, an error is represented with The goal of the method validation improvement is to adapt all violations to this. Method parameters that have nested This explains the difference you see in the error codes for some method parameters vs others. That said, when it comes to lists, arrays, and maps, we currently handle those as beans with nested violations, but as you have correctly pointed out they can also be lists with direct constraints on elements, leading to the inconsistency in how I'll make changes to ensure list, array, and map handling is independent of whether a method parameter is a bean with nested violations or simple type elements. This means |
@mcso, container element support now applies for any As mentioned before, error codes still don't reflect a container index. This is by design since error messages are for elements irrespective of their position within a list. However, you can get the container index from @Override
protected ResponseEntity<Object> handleHandlerMethodValidationException(
HandlerMethodValidationException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) {
ex.getBody().setProperty("errors", ex.getAllValidationResults().stream()
.flatMap(result -> result.getResolvableErrors().stream()
.map(error -> {
String param = (error instanceof ObjectError objectError ?
objectError.getObjectName() :
((MessageSourceResolvable) error.getArguments()[0]).getDefaultMessage());
param = (result.getContainerIndex() != null ?
param + "[" + result.getContainerIndex() + "]" : param);
return Map.of("parameter", param, "error", error.getDefaultMessage());
}))
.toList());
return super.handleHandlerMethodValidationException(ex, headers, status, request);
} If you could you check with |
Hope you had pleasant holidays, and a happy New Year. I admit I used the codes as an indicator/proof for this ticket that things were handled differently, not really something I have used in my code. It was only when trying to figure out differences between the two exceptions I noticed these were different as well. This change allows me to get rid of a really ugly hack with reflection, in order to achieve the same result. So this is very much appreciated, and my primary objective is solved. It could be on the endless TODO list to look at, if |
Happy New Year, and thanks for the additional feedback!
We continue to raise |
Affects: 6.1.1
With the method validation improvement in 6.1, a few inconsistencies compared to bean validation. I could imagine there are usecases I am not aware of being the reason, but it seems like the two types could be a lot more aligned.
Validation of the above snippet will result in the object name when handling the
HandlerMethodValidationException
to be "stringList". Had the parameter been a plain String, you can get the name of the parameter as expected. With bean validation, it also manages to tell the correct field path, name, and index.In addition, the error for the invalid list when using
HandlerMethodValidationException.getAllErrors()
doesn't contain information about which index had the validation failure. You can reconstruct this information by usingHandlerMethodValidationException.getAllValidationResults()
instead, as the object there does contain index information.As a sidenote. When looking at the
codes
field when handling the error, it seems to be very different for a String parameter and a list.String parameter:
List parameter:
Controller and parameter name is not present there either, generally making it look like lists are not handled in a similar way that the String parameter is.
As a continuation of the inconsistency above, when handling the exception afterwards, extracting the validation failure information is inconsistent.
For bean validation, it seems like the errors are always type
FieldError
(reallySpringValidationAdapter#ViolationFieldError
, but that is private), making it consistent across the different field types in your beans. MethodArgumentNotValidException.getAllErrors() is returningList<ObjectError>
.Method validation is less consistent.
HandlerMethodValidationException.getAllErrors()
return List<? extends MessageSourceResolvable>, and the specific type ofMessageSourceResolvable
differs depending if it is a String or a list parameter. For a list, it isObjectError
(SpringValidationAdapter#ViolationObjectError
), and for String it isDefaultMessageSourceResolvable
, making you have to consider the specific type if you want consistent error information. If you want the field name:String:
((MessageSourceResolvable) messageSourceResolvable.getArguments()[0]).getDefaultMessage()
List:
((ObjectError) messageSourceResolvable).getObjectName()
This can also be seen in the sidenote from point 1, the object name is not in the same place in either of the examples.
Demo project: demo.zip
The text was updated successfully, but these errors were encountered: