5
\$\begingroup\$

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!

Peilonrayz
44.4k7 gold badges80 silver badges157 bronze badges
asked Jun 22, 2021 at 17:11
\$\endgroup\$
3
  • 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\$ Commented Jun 23, 2021 at 12:41
  • 1
    \$\begingroup\$ Yes, it works as expected, then it can be closed. \$\endgroup\$ Commented 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\$ Commented Jun 23, 2021 at 13:01

0

Know someone who can answer? Share a link to this question via email, Twitter, or Facebook.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.