0

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;
    }
}
La Hai
  • 113
  • 2
  • 12
  • Can you reveal your `PostProduct`? And how do you call your API w/o body? – pirho Dec 05 '20 at 13:29
  • Can u share the ConrollerAdvice method and where is the use of RequestBody, you talking about ? – Nakul Goyal Dec 05 '20 at 13:51
  • @NakulGoyal I just updated the required parts. Please have a look – La Hai Dec 05 '20 at 14:56
  • @pirho with `application/x-www-form-urlencoded` and `multipart/form-data`, i dont think i can use `RequestBody` – La Hai Dec 05 '20 at 14:59
  • @NakulGoyal if i write the code like this `@RequestBody @Valid PostProduct postProduct`, the controllerAdvice method will be invoked, but i need the request to send image as well, so Json is not an option. Hence, `@RequestBody` is deleted – La Hai Dec 05 '20 at 15:02
  • Have u tried using @RestControllerAdvise and @ExceptionHandler(MethodArgumentNotValidException.class) ? – Nakul Goyal Dec 05 '20 at 16:02
  • @NakulGoyal Sorry, still nothing. – La Hai Dec 05 '20 at 17:45
  • @LaHai Have you tried this `https://stackoverflow.com/a/51334407/5001937` – Suraj Dec 05 '20 at 21:15
  • Thank you guys for your help. I found out the reason by looking at it in a different way. Please have a look. – La Hai Dec 06 '20 at 03:20

1 Answers1

-1

Found the Solution here BindException thrown instead of MethodArgumentNotValidException

Basically, when your content type is not application/json, BindException will be thrown, otherwise MethodArgumentNotValidException will be.

La Hai
  • 113
  • 2
  • 12
  • From the stacktrace you should know which exception is actually thrown. – Nakul Goyal Dec 06 '20 at 06:38
  • @NakulGoyal that's the problem, if you don't override BindException method, it will not show stacktrace or anything, only when i comment out ControllerAdvice, then it printed the stacktrace. So, please no downvote. – La Hai Dec 06 '20 at 07:30