I have a custom validator and need to include message parameters to construct the error message dynamically.
public class DescriptionLengthValidator
implements ConstraintValidator<ValidTypeDescriptionLength, RequestDto> {
@Override
public boolean isValid(RequestDto request, ConstraintValidatorContext context) {
int maxSize = request.getType().equals("Category1") ? 50 : 250;
boolean isValid = request.getDescription().length() <= maxSize;
if (!isValid) {
HibernateConstraintValidatorContext hibernateContext =
context.unwrap(HibernateConstraintValidatorContext.class);
hibernateContext.disableDefaultConstraintViolation();
hibernateContext.addMessageParameter("0", "0").addMessageParameter("1", maxSize)
.buildConstraintViolationWithTemplate("error.Size").addPropertyNode("description")
.addConstraintViolation();
return false;
}
return true;
}
}
Annotation is defined as follows.
@Constraint(validatedBy = DescriptionLengthValidator.class)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidTypeDescriptionLength {
String message() default "error.Size";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
The Controller advice is as follows.
@ControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
HttpHeaders headers, HttpStatus status, WebRequest request) {
Map<String, String> fieldErrors = ex.getBindingResult().getFieldErrors().stream().collect(
Collectors.toMap(FieldError::getField, fe -> getFieldErrorMessage(fe,
String.format("Invalid value [%s]", fe.getRejectedValue()))));
return handleFieldValidationErrors(ex, status, request, fieldErrors);
}
private String getFieldErrorMessage(FieldError error, String defaultMessage) {
Object[] args = error.getArguments();
if (args != null && args.length > 0 && args[0] instanceof MessageSourceResolvable) {
args = Arrays.copyOfRange(args, 1, args.length);
}
List<String> errorCodes = new ArrayList<>();
if (error.getCodes() != null) {
Arrays.stream(error.getCodes()).map(s -> "error." + s).forEach(errorCodes::add);
}
if (error.getDefaultMessage() != null) {
errorCodes.add(error.getDefaultMessage());
}
return service.getMessage(args, defaultMessage);
}
}
When accessing arguments by calling error.getArguments(), message parameters are not available. How can I modify custom validator/Controller advice to access massage parameters?