This is my validation class which implements ConstraintValidator
@Slf4j
public class DocumentMetaDataValidation implements ConstraintValidator<DocumentMetaDataValidator, DocumentMetaDataApplicationRequest> {
@Override
public boolean isValid(DocumentMetaDataApplicationRequest dataApplicationRequest, ConstraintValidatorContext constraintValidatorContext) {
constraintValidatorContext.disableDefaultConstraintViolation();
if(!Objects.nonNull(dataApplicationRequest)) {
log.error("Request Parameter is null/empty : ");
constraintValidatorContext
.buildConstraintViolationWithTemplate("Required parameter DocumentMetaDataApplicationRequest cannot be null/empty")
.addConstraintViolation();
return false;
}
Set<String> documentTypeSet=new HashSet<>();
dataApplicationRequest.getDocumentDetails().stream().forEach(documentDetails ->
documentTypeSet.add(documentDetails.getDocumentType()));
if (documentTypeSet.size()!=dataApplicationRequest.getDocumentDetails().size()){
log.error("Duplicate document type present ");
constraintValidatorContext
.buildConstraintViolationWithTemplate("Duplicate document type present")
.addConstraintViolation();
return false;
}
return true;
}
}
This is my controller :
@PostMapping(path = "/{referenceId}")
public Mono<DocumentUploadResponse> upload(
@NotBlank(message = "reference Id cannot be blank")
@PathVariable(value = "referenceId") String referenceId,
@NotEmpty(message = "List should not be empty")
@DocumentValidator @RequestPart(value = "documents") List<FilePart> document,
@DocumentMetaDataValidator @Valid @NotNull(message = "DocumentMetadata cannot be null")
@RequestPart(value = "documentsMetaData") DocumentMetaDataApplicationRequest documentMetaDataApplicationRequest) {
log.info("inside DocumentStorageController : uploadDocument()");
return documentStorageService.upload(referenceId, document, documentMetaDataApplicationRequest);
}
This is my validator class
@Target( { FIELD, PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = DocumentMetaDataValidation.class)
public @interface DocumentMetaDataValidator {
public String message() default ErrorMessage.VALIDATION_ERROR;
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Instead of getting error as "Duplicate document type present" im getting "upload.DocumentMetaDataApplicationRequest : Duplicate document type present" where upload is the method in my controller and DocumentMetaDataApplicationRequest is the class that I am trying to validate.
I tried to go through documentation It seems its is appending something called "propertyPath" which Im not able to get rid of.
You can override the behaviour by implementing custom exception handler
@RestControllerAdvice
public class GlobalExceptionHandler extends DefaultHandlerExceptionResolver {
@ResponseStatus(BAD_REQUEST)
@ExceptionHandler(value = {MethodArgumentNotValidException.class})
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException exception) {
Map<String, String> errors = new HashMap<>();
exception.getBindingResult().getAllErrors().forEach((error) -> {
String fieldName = ((FieldError) error).getField();
String errorMessage = error.getDefaultMessage();
errors.put(fieldName, errorMessage);
});
return status(BAD_REQUEST).body(Collections.singletonMap("errors", errors));
}
}
In case of ConstraintVoilationException
you can add new exception handler
@ResponseStatus(BAD_REQUEST)
@ExceptionHandler(value = {ConstraintViolationException.class})
protected ResponseEntity<Object> handleConstraintVoilation(ConstraintViolationException exception) {
var violations = exception.getConstraintViolations();
var errs = violations.
stream().
map(ConstraintViolation::getMessage).
toList();
Map<String, String> errors = new HashMap<>();
return status(BAD_REQUEST).body(Collections.singletonMap("errors", errs));
}