I'm trying to intercept all exceptions that can happen in a REST API request, create a custom message to each one and to add them both to the response.
The request below has two errors, one in the field tipo
and other in the field formato
. The default behavior is to stop in the first exception and throw. And after this the deserialization of the request stops. But I want to intercept the two exceptions and accumulate them to show both custom messages in the response.
{
"titulo": "1984",
"autor": "Georgesss Orwell",
"editora": "Penguin Classics Companhia das Letras",
"tipo": "LIVsRO",
"formato": "FISIsCO",
"quantidadePaginas": "392",
"edicao": 1,
"anoEdicao": 2020,
"generos": ["Literatura britânica", "Ficção", "Ficção britânica", "Distopia"],
"acabamento": "BROCHURA",
"idioma": "PORTUGUES",
"pais": "BRASIL",
"quantideLivros": 1
}
I'm using Java 17 with Spring Boot 2.7.5 in Windows 10.
Below is the approach that I've tried:
I've created a Global Exception Handler:
@ControllerAdvice
public class GlobalExceptionHandler {
private List<Exception> exceptions = new ArrayList<>();
@ExceptionHandler(HttpMessageNotReadableException.class)
public ResponseEntity<Object> handleHttpMessageNotReadable(HttpMessageNotReadableException ex) {
exceptions.add(ex);
return ResponseEntity.badRequest().body("Erro na desserialização do JSON");
}
@ExceptionHandler(Exception.class)
public ResponseEntity<Object> handleException(Exception ex) {
exceptions.add(ex);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Erro interno do servidor");
}
@ExceptionHandler(AccumulatedExceptions.class)
public ResponseEntity<Object> handleAccumulatedExceptions(AccumulatedExceptions ex) {
List<String> exceptionMessages = new ArrayList<>();
for (Exception exception : ex.getExceptions()) {
exceptionMessages.add(exception.getMessage());
}
return ResponseEntity.badRequest().body(exceptionMessages);
}
@PostConstruct
public void clearExceptions() {
exceptions.clear();
}
public List<Exception> getExceptions() {
return exceptions;
}
}
With this custom exception:
public class AccumulatedExceptions extends RuntimeException {
private List<Exception> exceptions = new ArrayList<>();
public AccumulatedExceptions(List<Exception> exceptions) {
this.exceptions = exceptions;
}
public List<Exception> getExceptions() {
return exceptions;
}
}
And this is my controller:
@RestController
@RequestMapping(path = "livros")
@CrossOrigin
public class LivroController {
@Autowired
private LivroService service;
@Autowired
private LivroRepository livroRepository;
@Autowired
private LivroResponse response;
private GlobalExceptionHandler globalExceptionHandler;
public LivroController(GlobalExceptionHandler globalExceptionHandler) {
this.globalExceptionHandler = globalExceptionHandler;
}
@GetMapping(path = "getLivros")
public List<Livro> getLivros() {
return livroRepository.findAll();
}
@PostMapping(path = "addLivro")
public ResponseEntity<String> addLivro(@RequestBody LivroRequest request) {
List<Exception> exceptions = globalExceptionHandler.getExceptions();
if (!exceptions.isEmpty()) {
globalExceptionHandler.clearExceptions();
throw new AccumulatedExceptions(exceptions);
}
return ResponseEntity.ok("Livro criado com sucesso");
}
}
Is it possible to do what I want or did I go crazy?
Let me know if you need more information from my side.
Thanks in advance.