If i use @RequestBody
, everything works fine. However, i cannot use @RequestBody
when sending files.
@PostMapping
public ResponseEntity<?> postProduct(@Valid PostProduct postProduct, BindingResult bindingResult) {
if(bindingResult.hasErrors()) {
for (ObjectError objectError : bindingResult.getAllErrors()) {
System.out.println(objectError.toString());
}
}
return ResponseEntity.ok().build();
}
The error is still thrown but the handleMethodArgumentNotValid
of ControllerAdvice
is not invoked.
I don't understand this behavior.
UPDATE 1
Here's the PostProduct
class
@Data
public class PostProduct {
@NotBlank(message = "product name must not be blank")
private String name;
@NotEmpty
@UniqueElements
private List<@NotNull @Positive Integer> materials;
@NotEmpty
@UniqueElements
private List<@NotNull @Positive Integer> colors;
@NotNull
@Positive
private Integer price;
@NotNull
private List<@NotNull @ProductImageConstraint MultipartFile> images;
}
The ControllerAdvice
:
@ControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
System.out.println("handleMethodArgumentNotValid");
Map<String, String> errors = new HashMap<>();
List<ObjectError> objectErrors = ex.getBindingResult().getAllErrors();
return returnError(objectErrors);
}
public static ResponseEntity<Object> returnError(List<ObjectError> objectErrors) {
Map<String, String> errors = new HashMap<>();
objectErrors.forEach((error) -> {
String fieldName = ((FieldError) error).getField();
String errorMessage = error.getDefaultMessage();
errors.put(fieldName, errorMessage);
});
return ResponseEntity.badRequest().body(errors);
}
}
I use 1 custom validator, don't know it has anything to do with this strange behavior but i'll post it anyway.
@Documented
@Constraint(validatedBy = ProductImageValidator.class)
@Target( { FIELD, TYPE_USE })
@Retention(RetentionPolicy.RUNTIME)
public @interface ProductImageConstraint {
String message() default "not image or file empty";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
public class ProductImageValidator implements
ConstraintValidator<ProductImageConstraint, MultipartFile> {
@Override
public void initialize(ProductImageConstraint constraintAnnotation) {
}
@Override
public boolean isValid(MultipartFile image, ConstraintValidatorContext context) {
boolean isValid = false;
String contentType = image.getContentType();
if (contentType != null && contentType.contains("image") && !image.isEmpty()) {
isValid = true;
}
return isValid;
}
}