javaspring-bootspring-validator

Spring Boot request body validation add customize messages when input an invalid data type


I am using Spring Boot to create a POST request and I need to validate the request body based on user inputs. However, when the user inputS an invalid data type, the response shows nothing, just 400 bad request status. Can I add a message to show the user which field is an invalid data type?

For example: Here is my controller:

@RestController
@RequestMapping("/api/foo")
public class FooController {

  @PostMapping("/save")
  public void postFoo(@Valid @RequestBody Foo foo) {
    // do somethings
  }
}

And here is my Foo class:

public class Foo {
  @NotBlank
  private String name;
  private Integer age;

  // getter/setter
}

So now I post a request as below:

{
  "name": "Foo Name",
  "age": "A String"
}

The server will respond with the status 400 Bad request without any message. How can I put my message such as Age must be an integer.

Until now I only have a solution that changes Age to String and adds a @Pattern validation annotation.

public class Foo {
  @NotBlank
  private String name;
  @Pattern(regexp = "[0-9]*", message = "Age must be an intege")
  private String age;

  // getter/setter
}

Solution

  • Thanks, everybody. I found a way to add messages and respond to users can aware of the error by using ControllerAdvice and overriding the handleHttpMessageNotReadable method as example below:

    @ControllerAdvice
    public class ErrorHandlerConfig extends ResponseEntityExceptionHandler {
     @Override
    protected ResponseEntity<Object> handleHttpMessageNotReadable(HttpMessageNotReadableException ex, HttpHeaders headers,
                                                                  HttpStatus status, WebRequest request) {
        if (ex.getCause() instanceof InvalidFormatException) {
            InvalidFormatException iex = (InvalidFormatException) ex.getCause();
            List<Map<String, String>> errors = new ArrayList<>();
            iex.getPath().forEach(reference -> {
                Map<String, String> error = new HashMap<>();
                error.put(reference.getFieldName(), iex.getOriginalMessage());
                errors.add(error);
            });
    
            return handleExceptionInternal(ex, errors, new HttpHeaders(), apiError.getStatus(), request);
        }
        return super.handleHttpMessageNotReadable(ex, headers, status, request);
    }
    }
    

    The response will be:

    [
        {
            "testId": "Cannot deserialize value of type `java.lang.Long` from String \"accm\": not a valid Long value"
        }
    ]