If the validation in RestController
fails, I need to handle MethodArgumentNotValidException
and provide an errorMessage, that contains
info about all rejected fields of passed object. If any rejected field has @JsonProperty
annotation with non-empty value, then I need to replace field name with this value in errorMessage. What do you think about this implemenation:
Dto example:
public class Person {
@NotEmpty
private String name;
@JsonProperty("interests")
@NotNull
@NotEmpty
private List<String> hobbies;
// getters, setters, etc.
}
Invalid JSON passed to some RestController endpoint in request body:
{
"name": "",
"interests": null
}
Exception handler:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ApiError> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
String errorMessage = getRejectedJsonProperties(e).entrySet()
.stream()
.map(entry -> entry.getKey() + ": " + String.join(", ", entry.getValue()))
.collect(joining("; "));
return constructResponse(errorMessage, HttpStatus.BAD_REQUEST);
}
private Map<String, List<String>> getRejectedJsonProperties(MethodArgumentNotValidException e) {
Map<String, List<String>> rejectedProps = e.getBindingResult().getFieldErrors().stream()
.collect(groupingBy(FieldError::getField,
mapping(DefaultMessageSourceResolvable::getDefaultMessage, toList())));
Arrays.stream(e.getParameter().getParameterType().getDeclaredFields())
.filter(f -> rejectedProps.containsKey(f.getName()))
.filter(f -> f.isAnnotationPresent(JsonProperty.class) && !f.getAnnotation(JsonProperty.class).value().isEmpty())
.forEach(f -> rejectedProps.put(f.getAnnotation(JsonProperty.class).value(), rejectedProps.remove(f.getName())));
return rejectedProps;
}
// constructResponse method
}
At first in getRejectedJsonProperties()
I collect in Map
all rejected field names as keys and List
of error messages as value (e.g. {name=[must not be empty]; hobbies=[must not be null, must not be empty"]}
).
Then I take all declared fields of validated object and if field has JsonPropery
annotation I replace this entry with new key in rejectedProps
map.
As a result, the errorMessage
in handleMethodArgumentNotValidException()
:
name: must not be empty; interests: must not be null, must not be empty
If you need any clarifications, please let me know and thanks in advance!
-
1\$\begingroup\$ Welcome to the Code Review Community, is the code working as expected? We only review code that is working as expected. Please read How do I ask a good question?. Right now your question has three votes to close. \$\endgroup\$pacmaninbw– pacmaninbw ♦2021年06月23日 12:41:26 +00:00Commented Jun 23, 2021 at 12:41
-
1\$\begingroup\$ Yes, it works as expected, then it can be closed. \$\endgroup\$Georgii Lvov– Georgii Lvov2021年06月23日 12:46:50 +00:00Commented Jun 23, 2021 at 12:46
-
3\$\begingroup\$ To anyone in the close vote queue, this question was just discussed in the 2nd Monitor and we don't see any reason why it should be closed. It does need an answer. \$\endgroup\$pacmaninbw– pacmaninbw ♦2021年06月23日 13:01:44 +00:00Commented Jun 23, 2021 at 13:01