Menangani Exception Secara Global dengan @ControllerAdvice dan @RestControllerAdvice di Spring Boot

Pengenalan

Dalam pengembangan aplikasi Spring Boot, penanganan error yang konsisten dan terstruktur merupakan hal yang sangat penting. Spring Framework menyediakan mekanisme yang powerful untuk menangani exception secara global menggunakan anotasi @ControllerAdvice dan @RestControllerAdvice. Artikel ini akan membahas kedua anotasi tersebut beserta implementasi praktisnya.

Contoh RestControllerAdvice

Apa itu @ControllerAdvice?

@ControllerAdvice adalah anotasi yang memungkinkan kita untuk menangani exception secara global di seluruh aplikasi Spring. Dengan menggunakan anotasi ini, kita tidak perlu menulis blok try-catch di setiap controller atau method. Semua exception yang terjadi akan ditangkap dan diproses di satu tempat terpusat.

Karakteristik @ControllerAdvice:

  • Berlaku untuk semua controller dalam aplikasi
  • Dapat menangani berbagai jenis exception
  • Mendukung pembuatan response view (HTML, JSP, Thymeleaf)
  • Cocok untuk aplikasi web tradisional yang mengembalikan halaman HTML

Apa itu @RestControllerAdvice?

@RestControllerAdvice adalah versi khusus dari @ControllerAdvice yang dirancang untuk RESTful API. Anotasi ini merupakan kombinasi dari @ControllerAdvice dan @ResponseBody, yang artinya setiap response akan otomatis dikonversi menjadi JSON atau XML.

Karakteristik @RestControllerAdvice:

  • Khusus untuk REST API
  • Response otomatis di-serialize menjadi JSON/XML
  • Tidak perlu menambahkan @ResponseBody di setiap method handler
  • Cocok untuk aplikasi modern yang berbasis microservices

Perbedaan Utama

Aspek@ControllerAdvice@RestControllerAdvice
Response TypeView (HTML, JSP)JSON/XML
@ResponseBodyPerlu ditambahkan manualSudah included
Use CaseWeb tradisionalREST API
SerializationManualOtomatis

Implementasi GlobalExceptionHandler

Berikut adalah contoh implementasi @RestControllerAdvice yang menangani exception secara global:

package com.yusuf.springmongoclean.exception;

import com.yusuf.springmongoclean.dto.ErrorResponse;
import jakarta.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

import java.time.Instant;

@RestControllerAdvice
public class GlobalExceptionHandler {
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

@ExceptionHandler(IllegalArgumentException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ErrorResponse handleIllegalArgument(
IllegalArgumentException ex,
HttpServletRequest request
) {
return new ErrorResponse(
Instant.now(),
HttpStatus.BAD_REQUEST.value(),
ex.getMessage(),
request.getRequestURI()
);
}

@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ErrorResponse handleAll(Exception ex, HttpServletRequest request) {
log.error("Unhandled exception", ex);
return new ErrorResponse(
Instant.now(),
HttpStatus.INTERNAL_SERVER_ERROR.value(),
"Internal server error",
request.getRequestURI()
);
}
}

Penjelasan Kode:

1. @RestControllerAdvice Anotasi ini menandakan bahwa class ini adalah global exception handler untuk REST API.

2. @ExceptionHandler Anotasi ini menentukan jenis exception mana yang akan ditangani oleh method tersebut. Dalam contoh di atas, ada dua handler:

  • handleIllegalArgument: Menangani IllegalArgumentException
  • handleAll: Menangani semua exception lainnya sebagai fallback

3. @ResponseStatus Anotasi ini menentukan HTTP status code yang akan dikembalikan. Contohnya:

  • BAD_REQUEST (400) untuk invalid argument
  • INTERNAL_SERVER_ERROR (500) untuk error yang tidak terduga

4. ErrorResponse Object DTO yang berisi informasi error dengan struktur konsisten:

  • Timestamp: Waktu terjadinya error
  • Status Code: Kode HTTP status
  • Message: Pesan error
  • Path: URL endpoint yang error

5. Logging Method handleAll menggunakan logger untuk mencatat exception yang tidak tertangani, memudahkan debugging.

Contoh Class ErrorResponse

package com.yusuf.springmongoclean.dto;

import java.time.Instant;

public record ErrorResponse(
Instant timestamp,
int status,
String error,
String path
) {}

Contoh Kasus Yang Menggunakan ErrorResponse

Kita membuat dulu sebuah user dengan nama dan email Bunny

Ups, saat buat lagi user yang sama maka kita akan mentrigger exception

Contoh Response JSON

Ketika terjadi error, aplikasi akan mengembalikan response JSON seperti ini:

{
"timestamp": "2026-01-26T04:38:26.556849Z",
"status": 400,
"error": "Email already registered",
"path": "/auth/register"
}


Best Practices

1. Tangani Exception Spesifik Terlebih Dahulu

Urutkan handler dari yang paling spesifik ke yang paling general. Exception yang lebih spesifik harus ditangani sebelum exception parent-nya.

@ExceptionHandler(ProductNotFoundException.class) 
@ResponseStatus(HttpStatus.NOT_FOUND) public ErrorResponse handleProductNotFound(ProductNotFoundException ex) { 
    // Handler spesifik 
}


@ExceptionHandler(Exception.class) 
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) 
public ErrorResponse handleAll(Exception ex) { 
     // Handler general sebagai fallback 
}

2. Gunakan Logging yang Tepat

Log error yang serious (500) dengan level ERROR, sedangkan client error (400) bisa dengan level WARN atau tidak di-log sama sekali.

@ExceptionHandler(IllegalArgumentException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ErrorResponse handleIllegalArgument(
IllegalArgumentException ex,
HttpServletRequest request
) {
return new ErrorResponse(
Instant.now(),
HttpStatus.BAD_REQUEST.value(),
ex.getMessage(),
request.getRequestURI()
);
}

@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ErrorResponse handleAll(Exception ex, HttpServletRequest request) {
log.error("Unhandled exception", ex);
return new ErrorResponse(
Instant.now(),
HttpStatus.INTERNAL_SERVER_ERROR.value(),
"Internal server error",
request.getRequestURI()
);
}

3. Jangan Expose Informasi Sensitif

Untuk production, hindari menampilkan stack trace atau detail internal system kepada client.

@ExceptionHandler(Exception.class) 
public ErrorResponse handleAll(Exception ex) { 
    log.error("Internal error", ex); // Log detail lengkap 
    return new ErrorResponse( Instant.now(), 500, "Terjadi kesalahan pada server" path ); 
}

4. Buat Custom Exception

Untuk business logic yang spesifik, buat custom exception yang lebih deskriptif.

public class ProductNotFoundException extends RuntimeException {
    public ProductNotFoundException(String productId) { 
        super("Product not found with ID: " + productId); 
    } 
} 

@ExceptionHandler(ProductNotFoundException.class) 
@ResponseStatus(HttpStatus.NOT_FOUND) public ErrorResponse handleProductNotFound(ProductNotFoundException ex) { 
    return new ErrorResponse( Instant.now(), 404, ex.getMessage(), path ); 
}


Kapan Menggunakan @ControllerAdvice vs @RestControllerAdvice?

Gunakan @ControllerAdvice ketika:

  • Membangun aplikasi web tradisional dengan server-side rendering
  • Menggunakan template engine seperti Thymeleaf atau JSP
  • Ingin redirect ke halaman error custom

Gunakan @RestControllerAdvice ketika:

  • Membangun REST API
  • Response berupa JSON atau XML
  • Aplikasi berbasis microservices
  • Frontend terpisah (SPA dengan React, Vue, Angular)

Kesimpulan

@ControllerAdvice dan @RestControllerAdvice adalah fitur powerful dalam Spring Boot untuk menangani exception secara global dan konsisten. Dengan menggunakan anotasi ini, kita dapat:

  • Memisahkan logic penanganan error dari business logic
  • Membuat response error yang konsisten di seluruh aplikasi
  • Meningkatkan maintainability kode
  • Memberikan pengalaman yang lebih baik kepada client API

Untuk aplikasi REST API modern, @RestControllerAdvice adalah pilihan yang tepat karena otomatis mengkonversi response menjadi JSON tanpa perlu konfigurasi tambahan. Pastikan untuk selalu menerapkan best practices dalam implementasinya agar aplikasi lebih robust dan mudah di-maintain.


Comments

Popular posts from this blog

Numpang Kerja Remote dari Bandung Creative Hub

Membangun AI Development Assistant Lokal

Debugging PHP Web dengan XDebug di Intellij IDEA (PHP STORM)