2

I have DTO which I want to restrict for size:

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder(toBuilder = true)
public class CreateUserDTO {

    @NotNull
    @NotEmpty
    @Size(min=1, max=20, message = "'Login' value '${validatedValue}' must be between {min} and {max} characters long.")
    private String login;

    @NotNull
    @NotEmpty
    @Size(min=1, max=45, message = "'Email' value '${validatedValue}' must be between {min} and {max} characters long.")
    private String email;

    @NotNull
    @NotEmpty
    @Size(min=1, max=20, message = "'First name' value '${validatedValue}' must be between {min} and {max} characters long.")
    private String firstName;

    @NotNull
    @NotEmpty
    @Size(min=1, max=20, message = "'Last name' value '${validatedValue}' must be between {min} and {max} characters long.")
    private String lastName;
}

Rest controller:

    @PostMapping("/create")
    public ResponseEntity<?> create(@Valid @RequestBody CreateUserDTO dto) {

        .....

        return ok().build();
    }

Any idea why I get this huge error message:

{
    "errors": [
        {
            "status": 404,
            "code": "1001",
            "title": "Not found",
            "detail": "Validation failed for argument [0] in public org.springframework.http.ResponseEntity<?> org.engine.rest.UsersController.create(org.engine.dto.CreateUserDTO): [Field error in object 'createUserDTO' on field 'login': rejected value [56dtttttttttt444444444465st]; codes [Size.createUserDTO.login,Size.login,Size.java.lang.String,Size]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [createUserDTO.login,login]; arguments []; default message [login],20,1]; default message ['Login' value '56dtttttttttt444444444465st' must be between 1 and 20 characters long.]] ",
            "extra": {
                "detail": "Validation failed for argument [0] in public org.springframework.http.ResponseEntity<?> org.engine.rest.UsersController.create(org.engine.dto.CreateUserDTO): [Field error in object 'createUserDTO' on field 'login': rejected value [56dtttttttttt444444444465st]; codes [Size.createUserDTO.login,Size.login,Size.java.lang.String,Size]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [createUserDTO.login,login]; arguments []; default message [login],20,1]; default message ['Login' value '56dtttttttttt444444444465st' must be between 1 and 20 characters long.]] "
            }
        }
    ]
}
7
  • "56dtttttttttt444444444465st".length(); $4 ==> 27. If the value is not what you sent, try {value} instead of ${validatedValue}. Commented Jun 15, 2021 at 23:19
  • Show please how do you handle this exception Commented Jun 15, 2021 at 23:23
  • I use this code to handle exceptions: github.com/rcbandit111/OAuth2/tree/master/src/main/java/org/… Commented Jun 16, 2021 at 0:02
  • @PeterPenzov As the input passed is more than 20 chars,it throws the Validation Exception. Then it is handled by serverExceptionHandler which is defined inside EngineExceptionHandler.java which serves this response. Commented Jun 16, 2021 at 1:35
  • @PeterPenzov what version of spring boot / spring framework are you using? Commented Jun 20, 2021 at 14:42

5 Answers 5

2

Looking at the linked repo in your comment you could just add a new exception handler to customize constraint related validation errors.

Right now all the undefined exceptions are routed to as defined here.

You can define a exception handler for constraint related errors in the EngineExceptionhandler class.

Something like

@ExceptionHandler(ConstraintViolationException.class)
ResponseEntity<ErrorResponseDTO> constraintValidationException(final ConstraintViolationException e) {
    List<ErrorRerponse> errors = new ArrayList<>();
    for (ConstraintViolation violation : e.getConstraintViolations()) {
        ErrorResponse error = new ErrorResponse();
        error.setTitle(violation.getPropertyPath().toString());
        error.setDetail(violation.getMessage());
        errors.add(error);
    }
    ErrorResponseDTO errorResponse = new ErrorResponseDTO();
    errorResponse.setErrors(errors);
    return new ResponseEntity<ErrorResponseDTO>(errorResponse, HttpStatus.BAD_REQUEST);
}

You can add more customization based on your needs.

Sign up to request clarification or add additional context in comments.

Comments

1
+50

I'm using the following ResponseEntityExceptionHandler which works fine for me.

@Order(Ordered.HIGHEST_PRECEDENCE)
@ControllerAdvice
public class RestExceptionHandler extends ResponseEntityExceptionHandler {


  @Override
  protected ResponseEntity<Object> handleMethodArgumentNotValid(
      MethodArgumentNotValidException ex,
      HttpHeaders headers,
      HttpStatus status,
      WebRequest request) {
    Map<String, Map<String, List<Map<String, String>>>> errors = new HashMap<>();
    ex.getBindingResult()
        .getAllErrors()
        .forEach(
            error -> {
              String fieldName = ((FieldError) error).getField();
              String errorMessage = error.getDefaultMessage();
              Map<String, String> errorFields = new HashMap<>();
              errorFields.put("field", fieldName);
              errorFields.put("message", errorMessage);
              Map<String, List<Map<String, String>>> errorMap = new HashMap<>();
              errorMap.put("errors", List.of(errorFields));
              errors.put(fieldName, errorMap);
            });

    return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errors);
  }
}

Comments

1

Simply The error message says where the issue is

default message ['Login' value '56dtttttttttt444444444465st' must be between 1 and 20 characters long.]

Since the value, you passed to login in CreateUserDTO dto with the request having characters more than the max value you have defined(20). Since the validation is failed It throws this error.

Comments

1

You need to handle MethodArgumentNotValidException

A quick implementation would be like

@ExceptionHandler({ MethodArgumentNotValidException.class })
public ResponseEntity<Void> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
    BindingResult bindingResult = ex.getBindingResult();
    for (FieldError fieldError : bindingResult.getFieldErrors()) {
        // Do something with fieldError.getDefaultMessage();
        // Which is equivalent to 'Login' value '${validatedValue}' must be between {min} and {max} characters long.
    }

    for (ObjectError objectError : bindingResult.getGlobalErrors()) {
        // Do something with objectError.getDefaultMessage();
    }

    return ResponseEntity.ok().build();
}

Comments

1

You need to handle the root exception and beautify it before showing to end user or sending to client. As in mentioned above answers, you can override handleMethodArgumentNotValid method from ResponseEntityExceptionHandler as I did below:

@RestControllerAdvice
public class ServiceExceptionHandler extends ResponseEntityExceptionHandler {

    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
                                                                  HttpHeaders headers, HttpStatus status, WebRequest request) {

        StringBuilder sb = new StringBuilder();
        ex.getBindingResult().getAllErrors().forEach((error) -> {
            sb.append("[");
            sb.append(((FieldError) error).getField());
            sb.append(" ");
            sb.append(error.getDefaultMessage());
            sb.append("] ");
        });

    log.error("Method arg is invalid. " + sb.toString(), ex);

    return new ResponseEntity<>(sb.toString(), HttpStatus.BAD_REQUEST);
    }
}

log.error() prints the message below:

// here is the message I show to the end user
10:27:02 [ERROR] [ServiceExceptionHandler] 141: Method arg is invalid. [shareList size must be between '1' and '10'] 
// here is the stack trace you encountered
org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public
...
[Size.eyatTransferDTO.shareList,Size.shareList,Size.java.util.List,Size]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [eyatTransferDTO.shareList,shareList]; arguments []; default message [shareList],10,1]; default message [size must be between '1' and '10']]
...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.