
Quando si sviluppano applicazioni complesse, le eccezioni diventano inevitabili. Non importa quanto sia curato il codice: errori di validazione, dati mancanti o problemi interni prima o poi arrivano. Il punto non è evitarli del tutto, ma gestirli in modo pulito e coerente, evitando di disseminare il codice con blocchi try/catch
o risposte HTTP costruite a mano in ogni controller. È qui che entra in gioco la gestione centralizzata delle eccezioni, una delle pratiche più eleganti e potenti offerte da Spring Boot per mantenere ordine, leggibilità e coerenza nelle API.
Perché centralizzare la gestione delle eccezioni
Un’applicazione ben strutturata deve sapere comunicare chiaramente con chi la utilizza, che si tratti di un frontend o di un servizio esterno. Quando qualcosa va storto, la risposta deve essere prevedibile, leggibile e coerente con il resto dell’API. Senza una gestione centralizzata, ogni controller rischia di restituire errori in formati diversi, con messaggi incoerenti o codici di stato HTTP sbagliati. Questo genera confusione, rallenta il debug e complica l’integrazione.
Centralizzare significa creare un punto unico in cui tutte le eccezioni passano prima di arrivare al client. Da qui possiamo decidere cosa mostrare, cosa nascondere e come formattare la risposta.
@ControllerAdvice e @ExceptionHandler: il cuore del sistema
Spring Boot mette a disposizione due strumenti chiave per ottenere una gestione centralizzata elegante: @ControllerAdvice e @ExceptionHandler. Il primo intercetta le eccezioni lanciate dai controller, mentre il secondo indica come trattarle. Insieme formano una sorta di firewall per gli errori, che blocca ogni eccezione e la trasforma in una risposta HTTP strutturata.
Ecco un esempio concreto di implementazione:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(EntityNotFoundException.class)
public ResponseEntity<Map<String, Object>> handleEntityNotFound(EntityNotFoundException ex) {
Map<String, Object> body = new HashMap<>();
body.put("error", "Not Found");
body.put("message", ex.getMessage());
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(body);
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, Object>> handleValidationErrors(MethodArgumentNotValidException ex) {
Map<String, Object> body = new HashMap<>();
body.put("error", "Validation Error");
body.put("message", ex.getBindingResult().getAllErrors().get(0).getDefaultMessage());
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(body);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<Map<String, Object>> handleGenericException(Exception ex) {
Map<String, Object> body = new HashMap<>();
body.put("error", "Internal Server Error");
body.put("message", ex.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(body);
}
}
Questa classe intercetta tutte le eccezioni più comuni e costruisce una risposta JSON pulita. L’annotazione @RestControllerAdvice permette di estendere la logica a tutti i controller senza dover modificare nulla nel codice esistente. È una soluzione trasparente e non intrusiva.
Creare eccezioni personalizzate per maggiore chiarezza
In un’applicazione reale, è utile creare delle eccezioni specifiche per i diversi contesti. Ad esempio, per un’entità non trovata:
public class EntityNotFoundException extends RuntimeException {
public EntityNotFoundException(String message) {
super(message);
}
}
In questo modo, quando qualcosa non viene trovato nel database, si può semplicemente scrivere:
throw new EntityNotFoundException("Utente non trovato");
Spring intercetterà automaticamente l’eccezione e restituirà una risposta coerente e leggibile, senza dover riscrivere nulla nei controller.
I vantaggi reali della gestione centralizzata
-
Codice più pulito: nessun blocco
try/catch
ripetuto in ogni metodo. -
Coerenza: tutti gli errori vengono restituiti con lo stesso formato JSON.
-
Manutenzione facilitata: basta modificare una sola classe per cambiare la gestione di tutti gli errori.
-
Maggiore controllo: è possibile decidere quali messaggi mostrare al client e quali nascondere per motivi di sicurezza.
Conclusione
La gestione centralizzata delle eccezioni non è un dettaglio secondario, ma una parte fondamentale della qualità di un’API. Un sistema che restituisce errori chiari, coerenti e ben formattati è un sistema più professionale, più facile da mantenere e più semplice da integrare. In Spring Boot basta una classe con @RestControllerAdvice per ottenere tutto questo. È uno di quegli strumenti che, una volta introdotti nel progetto, fanno chiedere come si sia potuto sviluppare senza di esso. Daje.