Here are some of approaches you can follow to handle your custom exceptions.

Create a POJO to handle your custom error messages and put your properties you want to return.

public class ErrorResponse {
     private String message;

     public String getMessage() {
       return message;
    }

    public void setMessage(String message) {
      this.message = message;
    }
}

Approach 1. Within your Controller method.

    @RequestMapping("/car/{id}")
    public ResponseEntity<?> getCar(@PathVariable String id) {
        Car car = carService.getCar(id);
        if (car == null) {
          ErrorResponse errorResponse = new ErrorResponse();
          errorResponse.setMessage("Record not found");
          return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND)
         }
       return new ResponseEntity<>(car, HttpStatus.OK); 
    }    

Approach 2: Handle exceptions globally.

Step 1: Create NotFound exception class and extend to RunTime Exception.

public class NoRecordFoundException extends RuntimeException {

    public NoRecordFoundException() {
        super();
    }
}

Step 2: Create Global Exception handler

@RestControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(NoRecordFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
@ResponseBody
public ErrorResponse handleNoRecordFoundException(NoRecordFoundException ex) 
{

    ErrorResponse errorResponse = new ErrorResponse();
    errorResponse.setMessage("No Record Found");
    return errorResponse;
}

//same you can handle Exceptionerror for internal

@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseBody
public ErrorResponse handleDefaultException(Exception ex) {
    ErrorResponse response = new ErrorResponse();
    response.setMessage(ex.getMessage());
    return response;
}
}

Step 3: throw Not found exception from your controller or service:

        @RequestMapping("/car/{id}")
        public ResponseEntity<?> getCar(@PathVariable String id) {
            Car car = carService.getCar(id);
            if (car == null) {
             throw new NoRecordFoundException();
             }
           return new ResponseEntity<>(car, HttpStatus.OK); 
        }    

Approach 3: Create @ExceptionHandler within controller and throw

 @ExceptionHandler(NoRecordFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ResponseBody
    public ErrorResponse handleNoRecordFoundException(NoRecordFoundException ex) {

        ErrorResponse errorResponse = new ErrorResponse();
        errorResponse.setMessage("No Record Found");
        return errorResponse;
    }
Answer from kj007 on Stack Overflow
Top answer
1 of 3
18

Here are some of approaches you can follow to handle your custom exceptions.

Create a POJO to handle your custom error messages and put your properties you want to return.

public class ErrorResponse {
     private String message;

     public String getMessage() {
       return message;
    }

    public void setMessage(String message) {
      this.message = message;
    }
}

Approach 1. Within your Controller method.

    @RequestMapping("/car/{id}")
    public ResponseEntity<?> getCar(@PathVariable String id) {
        Car car = carService.getCar(id);
        if (car == null) {
          ErrorResponse errorResponse = new ErrorResponse();
          errorResponse.setMessage("Record not found");
          return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND)
         }
       return new ResponseEntity<>(car, HttpStatus.OK); 
    }    

Approach 2: Handle exceptions globally.

Step 1: Create NotFound exception class and extend to RunTime Exception.

public class NoRecordFoundException extends RuntimeException {

    public NoRecordFoundException() {
        super();
    }
}

Step 2: Create Global Exception handler

@RestControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(NoRecordFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
@ResponseBody
public ErrorResponse handleNoRecordFoundException(NoRecordFoundException ex) 
{

    ErrorResponse errorResponse = new ErrorResponse();
    errorResponse.setMessage("No Record Found");
    return errorResponse;
}

//same you can handle Exceptionerror for internal

@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseBody
public ErrorResponse handleDefaultException(Exception ex) {
    ErrorResponse response = new ErrorResponse();
    response.setMessage(ex.getMessage());
    return response;
}
}

Step 3: throw Not found exception from your controller or service:

        @RequestMapping("/car/{id}")
        public ResponseEntity<?> getCar(@PathVariable String id) {
            Car car = carService.getCar(id);
            if (car == null) {
             throw new NoRecordFoundException();
             }
           return new ResponseEntity<>(car, HttpStatus.OK); 
        }    

Approach 3: Create @ExceptionHandler within controller and throw

 @ExceptionHandler(NoRecordFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ResponseBody
    public ErrorResponse handleNoRecordFoundException(NoRecordFoundException ex) {

        ErrorResponse errorResponse = new ErrorResponse();
        errorResponse.setMessage("No Record Found");
        return errorResponse;
    }
2 of 3
0

The best way to handle any app specific exceptions is to create a custom exception class. Create a package saying com.randomorg.appname.exception. In that create an appexception class that extends the Java's Exception class.

public class CustomAppException extends Exception {

    private String requestId;

    // Custom error message
    private String message;

    // Custom error code representing an error in system
    private String errorCode;

    public CustomAppException (String message) {
            super(message);
            this.message = message;
        }

        public CustomAppException (String requestId, String message, String errorCode) {
            super(message);
            this.requestId = requestId;
            this.message = message;
            this.errorCode = errorCode;
        }

        public String getRequestId() {
            return this.requestId;
        }

        public void setRequestId(String requestId) {
            this.requestId = requestId;
        }

        @Override
        public String getMessage() {
            return this.message;
        }

        public void setMessage(String message) {
            this.message = message;
        }

        public String getErrorCode() {
            return this.errorCode;
        }

        public void setErrorCode(String errorCode) {
            this.errorCode = errorCode;
        }
    }
}

Once this is done, ensure your controller uses this exception, this way you can customize any exception to become app based.

In your case, your methods like addCar, getCar, you can say it throws CustomAppException and then you can handle it in a simple try catch block.

To improvise further, you can further specialize exception by extending the CustomAppException class, say MyCustomException extends CustomAppException, this way you can organize your exception handling better. Let me know if you need more help on this. Happy to help.

๐ŸŒ
Rosa Fiore
rosafiore.eu โ€บ home โ€บ how to throw custom exceptions with spring boot
How to Throw Custom Exceptions with Spring Boot - Rosa Fiore
August 20, 2020 - Now, the ExceptionResponseHandler handles any exception that the application throws. It returns the timestamp when the error occurred, the message from the exception, and the request they used. That should provide a client-side application enough information to handle the rest towards the user, without giving away too much information of the backend. With the general setup done, it is finally time to get to the custom exceptions in Spring Boot.
๐ŸŒ
Davidgiard
davidgiard.com โ€บ throwing-and-catching-custom-exceptions-in-a-java-spring-boot-application
Throwing and Catching Custom Exceptions in a Java Spring Boot Application
Let's create a custom exception to specifically handle missing arguments. This exception will inherit from Java's Exception class, as shown below. public class MissingArgumentsException extends Exception { public MissingArgumentsException(String errorMessage) { super(errorMessage); } public MissingArgumentsException(String errorMessage, Throwable err) { super(errorMessage, err); } }
๐ŸŒ
Medium
codefarm0.medium.com โ€บ understanding-and-building-custom-exceptions-in-spring-boot-part-1-823260f01f6d
Understanding and Building Custom Exceptions in Spring Boot(Part 1) | by Arvind Kumar | Medium
May 24, 2025 - Throwing a generic RuntimeException just doesnโ€™t cut it. Clients need more than just a stack traceโ€”they need context, clarity, and actionable information. Enter custom exceptions. ... In this series, weโ€™re going to build a Spring Boot Starter (letโ€™s call it springboot-exception-starter) ...
Top answer
1 of 1
3

Lets make a custom ResourceAlreadyExistsException class . It will extends the RuntimeException class, and you can add as many parameters to it as you like. I've kept it concise like this.

public class ResourceAlreadyExistsException extends RuntimeException {

    public ResourceAlreadyExistsException(String property, String value) {
        super(String.format(
            "Resource with property %s and value %s already exists." +
            "Make sure to insert a unique value for %s",
            property, value, property));
    }
}

Whenever I need to check for a unique resource, I can tell the user which specific property has what value that causes the error. Furthermore, I notify the user what action must be taken to avoid the error.

Say, I chose to use error *** for my ResourceAlreadyExistsException. Still, I need to hook up this error message to the ExceptionResponseHandler. The extra method is very similar to the method that we usually create for handling all exceptions. In fact, you can easily copy-paste this method for all the exceptions you have. All you have to do, is changing the Exception class to your exception and change the HttpStatus..

@ExceptionHandler(ResourceAlreadyExistsException.class)
public final ResponseEntity<ExceptionResponse> handleResourceAlreadyExistsException(
    ResourceAlreadyExistsException ex, WebRequest req) {
    ExceptionResponse exceptionResponse = new ExceptionResponse(
        new Date(),
        ex.getMessage(),
        req.getDescription(false)
    );
    return new ResponseEntity<>(exceptionResponse, HttpStatus.UNPROCESSABLE_ENTITY);
๐ŸŒ
Medium
medium.com โ€บ @aamine โ€บ customized-exception-handling-in-spring-boot-e4546e180a2d
Customized Exception Handling in Spring Boot | by Amal Amine | Medium
July 1, 2019 - Now, instead of throwing a generic exception, we can throw the CustomException we created. Now that weโ€™ve included plenty of details, letโ€™s hit the endpoint again. ... Looks like weโ€™re not quite there yet โ€” our CustomException is being intercepted by Javaโ€™s ResponseEntityExceptionHandler, which handles all runtime exceptions and returns a formatted ResponseEntity.
Top answer
1 of 2
4

It's because, following line does not return null, but an empty list.

Collection<Employee> result = this.employeeRepository.findByLastName(lastName);

You can either check for empty list as well for throwing Exception, or just return the empty list as well. I would not recommend throwing Exception for find/ search. I personally, throw any NotFoundException only for get methods like getById. Otherwise I just return the empty list.

if (result == null || result.isEmpty()) {
    throw new EmployeeNotFoundException(lastName);
}

Also, modification to Hey-men-wattsup's code to send error code, instead of throwing exception in the Controller. This will send 404, NotFound code.

@ExceptionHandler(EmployeeNotFoundException.class)
    public void handleException(EmployeeNotFoundException  e, , HttpServletResponse response) {
    response.sendError(HttpStatus.NOT_FOUND.value(), e.getMessage());
}

Spring Boot Test's MockMvc class combined with Mockito provides required methods to unit test a controller.

2 of 2
0

In case you're wondering about that EmployeeNotFoundException, it's thrown but not being handled. You need at least one @ExceptionHandler annotated method to handle it.

 @ExceptionHandler(EmployeeNotFoundException.class)
        public void handleException(EmployeeNotFoundException  e) {
        // do something
        }

Like so :

 @RestController
    @RequestMapping("/employee")
    public class EmployeeService {

        @Autowired
        private EmployeeRepository employeeRepository;

        @RequestMapping(value = "/findByLastName?{lastName}=", method = RequestMethod.GET)
        Object getEmployees(@PathVariable String lastName) {
            Collection<Employee> result = this.employeeRepository.findByLastName(lastName);
            if (result == null) {
                throw new EmployeeNotFoundException(lastName);
            }
            return result;
        }

       @ExceptionHandler(EmployeeNotFoundException.class)
        public void handleException(EmployeeNotFoundException  e) {
         System.out.println("Exception triggered");
        }

    }
๐ŸŒ
Auth0
auth0.com โ€บ blog โ€บ get-started-with-custom-error-handling-in-spring-boot-java
Get Started with Custom Error Handling in Spring Boot (Java)
Learn how to implement custom error handling logic in Spring Boot. You will see two approaches based on the @ControllerAdvice annotation. Similarly, you will learn how to deal with authentication and access denied errors in Spring Security.
Find elsewhere
๐ŸŒ
Medium
medium.com โ€บ @sergiusac โ€บ custom-exception-handling-in-spring-boot-6b9a4666dbb5
Custom exception handling in Spring Boot | by Sergey Chin | Medium
December 7, 2022 - Also, the getCityById method throws a custom ApplicationException with the information provided, such as the error code, message, and HTTP status. Next, we create a REST controller. import io.github.sergiusac.exceptionhandling.service.CityService; ...
๐ŸŒ
Medium
medium.com โ€บ nerd-for-tech โ€บ how-to-handle-custom-exceptions-in-spring-boot-6673047b1dc7
How to Handle Custom Exceptions in Spring Boot | by Kasun Dissanayake | Nerd For Tech | Medium
April 9, 2023 - You can add @ExceptionHandler annotation and inside the annotation, you can give MethodArgumentNotValidException class. It will redirect to this method when we got MethodArgumentNotValidException at the controller level.
Top answer
1 of 1
3

Normally your exception handler is the last layer of exception handling that you write as a developer. You normaly don't re-throw an exception because then it will be handed to default exception handling mechanism of the server that hosts your application.

You normally return a response with the error that you want the user to see.

Also throwing a RunntimeException will be matched in exception handling mechanism by almost all servers that I know as a 500 error. So the user will see a 500 error which seems like your backend failed and something is messed up.

If you can predict what can go wrong then don't let the user see a 500 error code but instead inform him for what is bad. In that case when you have received DataIntegrityViolationException it means that in one way or another the input that the user provided is wrong. So it can not be the backend that failed (500 error) but the user that had done a bad request (400 error).

It can also be a safety issue when the client can make the backend fail, and retrieve the stack trace from the default handling mechanism and know information about how the database is built.

Here is a custom exception that you can use in your application

public class ApplicationException extends RuntimeException  {

    private CustomError customError;

    public ApplicationException(CustomError customError){
        super();
        this.customError = customError;
    }
}

And here is an error model class

@Getter
@Setter
@NoArgsConstructor
public class CustomError {

    private int code;
    private String message;
    private String cause;

    public CustomError(int code, String message, String cause) {
        this.code = code;
        this.message = message;
        this.cause = cause;
    }
 }

And this is how your error handling method could be used to return a response that the user understands.

@ControllerAdvice
public class RestRepositoryExceptionHandler {
    
    @ExceptionHandler(ApplicationException.class)
    public ResponseEntity handleApplicationException(ApplicationException e) {
        return ResponseEntity.status(e.getCustomError().getCode()).body(e.getCustomError());
    }


   @ExceptionHandler({DataIntegrityViolationException.class})
    public ResponseEntity handle(Exception e, Locale locale) {
        return ResponseEntity.status(400).body(new CustomError(400, e.getMessage(), "this is the cause that the user will see"));
  }
}

The following line could be reused anywhere in your application like (Controllers, Services, Daos,...)

throw new ApplicationException( new CustomError(400, "This is the error message that the user will see", "this is the cause that the user will see"));

You can of course modify the error code and not throw only 400, and also modify the errorMessage and errorCause in CustomError before throwing the ApplicationException

๐ŸŒ
Stack Overflow
stackoverflow.com โ€บ questions โ€บ 62920296 โ€บ implementing-custom-exceptions-in-spring-boot
java - Implementing custom exceptions in Spring Boot - Stack Overflow
We can go one step further and throw custom exception from Controller class (say ResourceException) which will wrap ServiceException.
Top answer
1 of 1
1

Before throwing an exception, it would be interesting to ask some questions like : Do I only need a custom error to return to the user in a specific controller or endpoint ? Or do I have to set a consistent error responses across the API with centralizing error handling ?

Depending on the need, you can add or not exception throwing. So you have two approches :

1 - Returning a ResponseEntity with an Error Code Directly (for quick responses with minimal logic): lets say all we want is returning an error because we know that the response is not the right one :

@GetMapping("/example-failure")
    public ResponseEntity<String> getExampleFailure() {
        //Return a response of type String instead of MyResponseType.
        String response = "This is an invalid response";
        return new ResponseEntity<>(response, HttpStatus.NOT_ACCEPTABLE);
    }

2 - If you really need an exception handling knowing that exceptions are often reserved for truly exceptional cases or errors that need to propagate up the stack but can also be used for consistent error responses across your API.

  • One of the best practices for handling exceptions globally is to use @ControllerAdvice :

        @GetMapping("/example-failure")
        public ResponseEntity<String> getExampleFailure() {
            // **Throw a new exception**
            throw new InvalidResponseTypeException("Item not found")
    
        }
        ...
    
    
        // Here The GlobalExceptionHandler declared in the controller advice class, catches the thrown exception and responds with a consistent error
        @ControllerAdvice
        public class GlobalExceptionHandler {
    
            @ExceptionHandler(InvalidResponseTypeException.class)
            public ResponseEntity<ErrorResponse> handleNotFoundException(InvalidResponseTypeException ex) {
                ErrorResponse error = new ErrorResponse("NOT_ACCEPTABLE", ex.getMessage());
                return new ResponseEntity<>(error, HttpStatus.NOT_ACCEPTABLE);
            }
    
            // You can also have in the same class other exception handlers...
        }
    
    
๐ŸŒ
DEV Community
dev.to โ€บ shadowphoenix โ€บ how-to-throw-custom-exceptions-with-spring-boot-2dd4
How to Throw Custom Exceptions with Spring Boot - DEV Community
August 20, 2020 - With the class for ExceptionResponse done, I can now start with handling the thrown exceptions. For this, I've created the ExceptionResponseHandler that inherits the ResponseEntityExceptionHandler class. It is also annotated with @ControllerAdvice. This annotation allows me to create one class that handles all exceptions for every controller in my application.
๐ŸŒ
DEV Community
dev.to โ€บ isaactony โ€บ exception-handling-in-spring-boot-2lgd
Exception Handling in Spring Boot - DEV Community
July 24, 2024 - package com.example.SpringBootRefresher.controller; import com.example.SpringBootRefresher.exception.DepartmentNotFoundException; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class DepartmentController { @GetMapping("/department") public String getDepartment() { // Simulate an exception throw new DepartmentNotFoundException("Department not found!"); } @ExceptionHandler(DepartmentNotFoundException.class) public ResponseEntity<String> handleDepartmentNotFoundException(DepartmentNotFoundException ex) { return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND); } }
๐ŸŒ
TutorialsPoint
tutorialspoint.com โ€บ spring_boot โ€บ spring_boot_exception_handling.htm
Spring Boot - Exception Handling
package com.tutorialspoint.demo.exception; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; @ControllerAdvice public class ProductExceptionController { @ExceptionHandler(value = ProductNotfoundException.class) public ResponseEntity<Object> exception(ProductNotfoundException exception) { return new ResponseEntity<>("Product not found", HttpStatus.NOT_FOUND); } } The Product Service API controller file is given below to updat