My Spring Boot application provides the following REST controller:
@RestController @RequestMapping("/api/verify") public class VerificationController { final VerificationService verificationService; Logger logger = LoggerFactory.getLogger(VerificationController.class); public VerificationController(VerificationService verificationService) { this.verificationService = verificationService; } @GetMapping public void verify( @RequestParam(value = "s1") String s1, @RequestParam(value = "s2") String s2) { try { verificationService.validateFormat(s1, s2); } catch (InvalidFormatException e) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST, e.getMessage()); } } }
In case validateFormat()
throws the InvalidFormatException
the client gets a HTTP 400 which is correct. The default JSON response body however looks like this:
{ "timestamp": "2020-06-18T21:31:34.911+00:00", "status": 400, "error": "Bad Request", "message": "", "path": "/api/verify" }
The message
value is always empty even if I hard-code it like this:
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "some string");
This is the exception class:
public class InvalidFormatException extends RuntimeException { public InvalidFormatException(String s1, String s2) { super(String.format("Invalid format: [s1: %s, s2: %s]", s1, s2)); } }
Define a class that extends the RuntimeException class. You can define the @ExceptionHandler method to handle the exceptions as shown. This method should be used for writing the Controller Advice class file. Now, use the code given below to throw the exception from the API.
You have to provide implementation to use your error handler, map the response to response entity and throw the exception. Create new error exception class with ResponseEntity field. Custom error handler which maps the error response back to ResponseEntity.
Altogether, the most common way is to use @ExceptionHandler on methods of @ControllerAdvice classes so that the exception handling will be applied globally or to a subset of controllers. ControllerAdvice is an annotation introduced in Spring 3.2, and as the name suggests, is “Advice” for multiple controllers.
This behavior has changed with Spring Boot 2.3 and is intentional. See release notes for details.
Setting server.error.include-message=always
in the application.properties
resolves this issue.
Setting server.error.include-message=always
disclosures messages of internal exceptions and this might be a problem in production environment.
An alternative approach is to use ExceptionHandler
. Here you can control what is transferred to client:
@ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(ResponseStatusException.class) public ResponseEntity<String> handleBadRequestException(ResponseStatusException ex) { // if you want you can do some extra processing with message and status of an exception // or you can return it without any processing like this: return new ResponseEntity<>(ex.getMessage(), ex.getStatus()); } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With