Skip to content

Commit a27056e

Browse files
updated
1 parent bb5a9fb commit a27056e

File tree

1 file changed

+34
-29
lines changed

1 file changed

+34
-29
lines changed

README.md

Lines changed: 34 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,12 @@ title.sample.problem=Some title
529529
detail.sample.problem=Some message details
530530
```
531531

532+
> [!WARNING]
533+
> It uses Spring's `MessageSource` to resolve placeholders in message template.
534+
> You should be aware that the single quote character (') fulfils a special purpose inside message patterns.
535+
> The single quote is used to represent a section within the message pattern that will not be formatted.
536+
> A single quote itself must be escaped by using two single quotes ('').
537+
532538
But exceptions come with some default attributes as follows, to minimize the number of properties required to be defined in `properties` file
533539

534540
If the messages are not found in `properties` files, defaults are taken as follows.
@@ -741,43 +747,42 @@ class CustomErrorResponseBuilder implements ErrorResponseBuilder<ServerWebExchan
741747
Any autoconfigured advice can be customized by overriding the same and providing a different implementation.
742748
Make sure to add annotation `@Order(Ordered.HIGHEST_PRECEDENCE)` over the class,
743749
It makes this handler to take precedence over the fallback advice which handles `Throwable` i.e. for all exceptions for which no `ControllerAdvice`s are defined.
750+
In case of Constraint Violation exceptions, the `errorKey` is derived from the field name,
751+
but in cases where field name is customized using `@JsonProperty`,
752+
`MethodArgumentNotValidException` may need to be customized to use `@JsonProperty` instead of class's field name in dynamically generated `erroKey` as follows
744753

745754
> For Spring Web applications
746755
```java
747756
@ControllerAdvice
748757
@Order(Ordered.HIGHEST_PRECEDENCE) // Important to note
749758
class CustomMethodArgumentNotValidExceptionHandler implements MethodArgumentNotValidAdviceTrait<NativeWebRequest, ResponseEntity<ProblemDetail>> {
750759

751-
public ResponseEntity<ProblemDetail> handleMethodArgumentNotValid(final MethodArgumentNotValidException exception, final NativeWebRequest request) {
752-
List<String> violations = processBindingResult(exception.getBindingResult());
753-
final String errors = violations.stream()
754-
.collect(Collectors.joining(", "));
755-
Problem problem = Problem.code(ProblemUtils.statusCode(HttpStatus.BAD_REQUEST)).title(HttpStatus.BAD_REQUEST.getReasonPhrase())
756-
.detail(errors).build();
757-
return create(exception, request, HttpStatus.BAD_REQUEST,
758-
problem);
759-
}
760-
761-
List<String> processBindingResult(final BindingResult bindingResult) {
762-
final List<String> fieldErrors =
763-
bindingResult.getFieldErrors().stream()
764-
.map(fieldError -> fieldError.getField() + ": " + fieldError.getDefaultMessage())
765-
.toList();
766-
final List<String> globalErrors =
767-
bindingResult.getGlobalErrors().stream()
768-
.map(
769-
objectError ->
770-
objectError.getObjectName() + ": " + objectError.getDefaultMessage())
771-
.toList();
772-
773-
final List<String> errors = new ArrayList<>();
774-
if (CollectionUtils.isNotEmpty(fieldErrors)) {
775-
errors.addAll(fieldErrors);
776-
}
777-
if (CollectionUtils.isNotEmpty(globalErrors)) {
778-
errors.addAll(globalErrors);
760+
@Override
761+
public ViolationVM handleFieldError(final FieldError fieldError, final Throwable exception) {
762+
String field = fieldError.getField();
763+
764+
try {
765+
if (fieldError.contains(ConstraintViolation.class)) {
766+
final ConstraintViolation<?> violation = fieldError.unwrap(ConstraintViolation.class);
767+
final Field declaredField = violation.getRootBeanClass().getDeclaredField(fieldError.getField());
768+
final JsonProperty annotation = declaredField.getAnnotation(JsonProperty.class);
769+
770+
if (annotation != null && annotation.value() != null && !annotation.value().isEmpty()) {
771+
field = annotation.value();
772+
}
773+
}
774+
} catch (Exception ignored) {
775+
// Ignored
779776
}
780-
return errors;
777+
778+
HttpStatus status = defaultConstraintViolationStatus();
779+
ProblemMessageSourceResolver codeResolver =
780+
ProblemMessageSourceResolver.of(
781+
ProblemConstant.CONSTRAINT_VIOLATION_CODE_CODE_PREFIX, fieldError, status.value());
782+
ProblemMessageSourceResolver messageResolver =
783+
ProblemMessageSourceResolver.of(
784+
ProblemConstant.CONSTRAINT_VIOLATION_DETAIL_CODE_PREFIX, fieldError);
785+
return createViolation(codeResolver, messageResolver, field);
781786
}
782787
}
783788
```

0 commit comments

Comments
 (0)