Exception Handling
Gracefully handle errors with @BotExceptionHandler.
@BotExceptionHandler
Catch specific exceptions in a handler:
@BotExceptionHandler(IllegalArgumentException.class)
public String handleValidationError(IllegalArgumentException e) {
return "Validation failed: " + e.getMessage();
}
@BotExceptionHandler(SQLException.class)
public String handleDatabaseError(SQLException e) {
log.error("Database error", e);
return "Sorry, a database error occurred.";
}
Scope: The containing @BotController class only.
Multiple Exception Handlers
@BotController
public class MyBot {
@BotExceptionHandler(IllegalArgumentException.class)
public String handleValidation(IllegalArgumentException e) {
return "Invalid input: " + e.getMessage();
}
@BotExceptionHandler(NullPointerException.class)
public String handleNull(NullPointerException e) {
return "Null error occurred";
}
@BotExceptionHandler(Exception.class)
public String handleGeneric(Exception e) {
return "An error occurred";
}
}
Most specific exception handler is tried first. If no match, generic handlers catch it.
@BotControllerAdvice
Global exception handling across all @BotController classes:
@BotControllerAdvice
public class GlobalExceptionHandler {
@BotExceptionHandler(UnauthorizedException.class)
public String handleUnauthorized(UnauthorizedException e) {
return "You don't have permission!";
}
@BotExceptionHandler(Exception.class)
public String handleAll(Exception e) {
log.error("Unhandled exception", e);
return "Sorry, an error occurred!";
}
}
Optional scope by packages, types, or annotations:
// Scope to specific packages
@BotControllerAdvice(basePackages = "com.example.payment")
public class PaymentExceptionHandler { ... }
// Scope to specific classes
@BotControllerAdvice(assignableTypes = PaymentController.class)
public class PaymentHandler { ... }
// Scope to classes with specific annotation
@BotControllerAdvice(annotations = RequiresAuth.class)
public class AuthHandler { ... }
Exception Resolution Order
- Most specific handler in the same
@BotController - Generic handler in the same
@BotController - Most specific handler in
@BotControllerAdvice(matching scope) - Generic handler in
@BotControllerAdvice - Default error handling (sends generic message)
Example: Complete Error Handling
@BotController
public class OrderBot {
@Autowired
private OrderService orderService;
@BotCommand("/order")
public String placeOrder(@BotCommandQueryParam("id") String orderId) {
Order order = orderService.getOrder(orderId); // May throw OrderNotFoundException
return "Order: " + order.getName() + ", Price: $" + order.getPrice();
}
@BotExceptionHandler(OrderNotFoundException.class)
public String handleOrderNotFound(OrderNotFoundException e) {
return "Order not found: " + e.getOrderId();
}
@BotExceptionHandler(IllegalArgumentException.class)
public String handleValidation(IllegalArgumentException e) {
return "Invalid order ID format";
}
}
@BotControllerAdvice
public class GlobalHandlers {
@BotExceptionHandler(DatabaseException.class)
public String handleDatabase(DatabaseException e) {
log.error("Database error", e);
return "Database error - please try again later";
}
@BotExceptionHandler(Exception.class)
public String handleGeneric(Exception e) {
log.error("Unexpected error", e);
return "Sorry, an unexpected error occurred!";
}
}
Logging Errors
@BotExceptionHandler(Exception.class)
public String handleError(Exception e) {
log.error("Handler failed", e); // Log before responding
return "An error occurred. Please try again.";
}
Testing Exception Handlers
@SpringBootTest
public class ErrorHandlingTest {
@Autowired
private MyBot bot;
@Test
public void testExceptionHandling() {
assertThrows(
IllegalArgumentException.class,
() -> bot.processOrder(null)
);
String response = bot.handleValidation(
new IllegalArgumentException("Invalid")
);
assertThat(response).contains("Validation failed");
}
}
Ready to learn about transports? Check out Transport Guides.