custom Exception Handler not throwing exception as expected

846 Views Asked by At

my expected output is:

{
   "message": " Invalid Booking Id ",
  "statusCode": 400
}

my current response is:

{
    "type": "about:blank",
    "title": "Internal Server Error",
    "status": 500,
    "detail": "Failed to write request",
    "instance": "/hotel/booking/1/transaction"
}

This indicates that an unhandled exception occurred in completePayment method, and the generic error handler is catching it, resulting in a 500 Internal Server Error.

The "InvalidPaymentException" issue arises due to an unhandled exception in the Spring Boot application. In the provided code, an "InvalidPaymentModeException" is thrown when the payment mode is not "UPI" or "CARD." However, this exception is not being caught and handled as expected. Instead, a generic exception handler meant for handling unexpected exceptions is invoked, resulting in a 500 Internal Server Error response.

ERROR RESPONSE DTO

                @NoArgsConstructor
                @AllArgsConstructor
                public class ErrorResponse {

                    private String message;
                    private int statusCode;

                }

EXCEPTION

                public class InvalidBookingIdException extends RuntimeException {

                    public InvalidBookingIdException (String message){
                        super(message);
                    }
                }

EXCEPTION HANDLER

                @ControllerAdvice

                public class CustomExceptionHandler extends ResponseEntityExceptionHandler {

                    private static final Logger log = LoggerFactory.getLogger(com.example.bookingservice.ExceptionHandler.CustomExceptionHandler.class);


                    @ExceptionHandler(InvalidPaymentModeException.class)
                    public ResponseEntity<com.example.bookingservice.dto.ErrorResponse> handleInvalidPaymentRequest(InvalidPaymentModeException ex, WebRequest request) {
                        log.error("InvalidPaymentModeException caught: " + ex.getMessage(), ex);

                        com.example.bookingservice.dto.ErrorResponse errorResponse = new com.example.bookingservice.dto.ErrorResponse(ex.getMessage(), HttpStatus.BAD_REQUEST.value());
                        return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST);
                    }
                }

CONTROLLER LAYER

                @RestController
                @RequestMapping(value = "/hotel")
                public class BookingController {


                    @Autowired
                    ModelMapper modelMapper;

                    @Autowired
                    BookingService bookingService;

                    @Autowired
                    RestTemplate restTemplate;

                    @PostMapping(value = "/booking/{id}/transaction", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
                    public ResponseEntity<?> completePayment(@PathVariable(name = "id") int id, @RequestBody TransactionRequestDto transactionRequestDto) {
                        try{
                            // Retrieve the booking based on the provided ID
                            Booking requestedBooking = bookingService.getBookingBasedOnId(id);

                            // Ensure that the transactionRequestDto contains the necessary data
                            System.out.println("Payment Request: " + transactionRequestDto.toString());

                            // Check if the payment mode is valid
                            String paymentMode = transactionRequestDto.getPaymentMode();
                            if (!bookingService.isValidPaymentMode(paymentMode)) {
                                throw new InvalidPaymentModeException("Invalid mode of payment");
                            }

                            // Define the URL for the Payment Service
                            String transactionGet_IdUrl = "http://localhost:8082/payment/transaction";

                            // Make the POST request to the Payment Service
                            ResponseEntity<Integer> transactionResponse = restTemplate.postForEntity(transactionGet_IdUrl, transactionRequestDto, Integer.class);

                            if (transactionResponse.getStatusCode() == HttpStatus.CREATED) {
                                int transactionId = transactionResponse.getBody();
                                System.out.println("Transaction ID: " + transactionId);

                                // Update the booking with the transaction ID
                                requestedBooking.setTransactionId(transactionId);
                                bookingService.updateBooking(id, requestedBooking);

                                // Map the updated booking to a response DTO
                                BookingResponseDto bookingResponseDto = modelMapper.map(requestedBooking, BookingResponseDto.class);

                                return new ResponseEntity<>(bookingResponseDto, HttpStatus.CREATED);
                            } else {
                                // Handle the case where the payment transaction was not successful
                                return ResponseEntity.status(transactionResponse.getStatusCode()).build();
                            }

                        } catch (Exception e){
                            com.example.bookingservice.dto.ErrorResponse errorResponseForOtherExceptions = new com.example.bookingservice.dto.ErrorResponse("Internal Server Error", HttpStatus.INTERNAL_SERVER_ERROR.value());
                            return new ResponseEntity(errorResponseForOtherExceptions,HttpStatus.INTERNAL_SERVER_ERROR);
                        }
                    }

                }

CONSOLE

Hibernate: insert into booking (aadhar_number,booked_on,from_date,num_of_rooms,room_numbers,room_price,to_date,transaction_id,booking_id) values (?,?,?,?,?,?,?,?,?)
In CrudRepository ,exiting save
In BookingServiceImpls ,exiting createBooking
In BookingController ,exiting createBooking
In BookingController ,entering completePayment
In BookingServiceImpls ,entering getBookingBasedOnId
In CrudRepository ,entering findById
Hibernate: select b1_0.booking_id,b1_0.aadhar_number,b1_0.booked_on,b1_0.from_date,b1_0.num_of_rooms,b1_0.room_numbers,b1_0.room_price,b1_0.to_date,b1_0.transaction_id from booking b1_0 where b1_0.booking_id=?
In CrudRepository ,exiting findById
In BookingServiceImpls ,exiting getBookingBasedOnId
Payment Request: TransactionRequestDto(paymentMode=other, bookingId=3, upiId=upi details, cardNumber=65757668687)
In BookingServiceImpls ,entering isValidPaymentMode
In BookingServiceImpls ,exiting isValidPaymentMode
In BookingController ,exiting completePayment
1

There are 1 best solutions below

0
lane.maxwell On

It's because of your try/catch block, InvalidPaymentModeException is never being thrown from your method.

In effect, you have this:

try {
  throw new InvalidPaymentModeException();
} catch (Exception e) {
  com.example.bookingservice.dto.ErrorResponse errorResponseForOtherExceptions = new com.example.bookingservice.dto.ErrorResponse("Internal Server Error", HttpStatus.INTERNAL_SERVER_ERROR.value());
  return new ResponseEntity(errorResponseForOtherExceptions,HttpStatus.INTERNAL_SERVER_ERROR);
}

So, the exception you're throwing is being caught and is never thrown from this method. This is why your advice isn't firing and instead, you're getting the output of return new ResponseEntity(errorResponseForOtherExceptions,HttpStatus.INTERNAL_SERVER_ERROR);