Best way to add the custom exception for the spring boot code
Asked Answered
H

3

12

How to display the appropriate error message when some exception occurs.

Suppose during GET methods if the data is not found, it should display the custom exception message.

Similarly if we are trying to delete the data which is not available.

Car.java

package com.car_rental_project.car_project;
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity

public class Car {

    @Id
    private String id;
    private String modelname;
    private String type;
    private String year_of_registration;
    private String seating_capacity;
    private String cost_per_day;
    private String milleage;
    private String pincode;
    private String contact_number;
    private String email;

    public Car() {

    }

    public Car(String id, String modelname, String type, String year_of_registration, String seating_capacity,String cost_per_day, String milleage, String pincode, String contact_number, String email) {
        super();
        this.id = id;
        this.modelname = modelname;
        this.type = type;
        this.year_of_registration = year_of_registration;
        this.seating_capacity = seating_capacity;
        this.cost_per_day = cost_per_day;
        this.milleage = milleage;
        this.pincode = pincode;
        this.contact_number = contact_number;
        this.email = email;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getModelname() {
        return modelname;
    }

    public void setModelname(String modelname) {
        this.modelname = modelname;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getYear_of_registration() {
        return year_of_registration;
    }

    public void setYear_of_registration(String year_of_registration) {
        this.year_of_registration = year_of_registration;
    }

    public String getSeating_capacity() {
        return seating_capacity;
    }

    public void setSeating_capacity(String seating_capacity) {
        this.seating_capacity = seating_capacity;
    }

    public String getCost_per_day() {
        return cost_per_day;
    }

    public void setCost_per_day(String cost_per_day) {
        this.cost_per_day = cost_per_day;
    }

    public String getMilleage() {
        return milleage;
    }

    public void setMilleage(String milleage) {
        this.milleage = milleage;
    }

    public String getPincode() {
        return pincode;
    }

    public void setPincode(String pincode) {
        this.pincode = pincode;
    }

    public String getContact_number() {
        return contact_number;
    }

    public void setContact_number(String contact_number) {
        this.contact_number = contact_number;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

CarService.java

package com.car_rental_project.car_project;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class CarService {

    @Autowired
    private CarRepository CarRepository;

    public List<Car> getAllCars() {
        return (List<Car>) CarRepository.findAll();
    }

    public Car getCar(String id) {
        return (Car) CarRepository.findOne(id);

    }

    public void addCar(Car car) {
        this.CarRepository.save(car);
    }

    public void updateCar(String id, Car car) {
        this.CarRepository.save(car);
    }

    public void deleteCar(String id) {
        this.CarRepository.delete(id);;
    }
}

CarController.java

package com.car_rental_project.car_project;

import java.util.List;    
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class CarController {

    @Autowired
    private CarService carService;

    @RequestMapping("/car")
    public List<Car> getAllCars() {
        return carService.getAllCars();
    }

    @RequestMapping("/car/{id}")
    public Car getCar(@PathVariable String id) {
        return carService.getCar(id);
            }

    //@PostMapping("/car")
    @RequestMapping(method=RequestMethod.POST, value="/car")
    public String addCar(@RequestBody Car car) {
        carService.addCar(car);
        String response = "{\"success\": true, \"message\": Car has been added successfully.}";
        return response;
    }

    //@RequestMapping(method=RequestMethod.PUT, value="/car/{id}")
    @PutMapping("/car/{id}")
    public String updateCar(@RequestBody Car car, @PathVariable String id) {
        carService.updateCar(id, car);
        String response = "{\"success\": true, \"message\": Car has been updated successfully.}";
        return response;
    }

    //@RequestMapping(method=RequestMethod.DELETE, value="/topics/{id}")
    @DeleteMapping("/car/{id}")
    public String deleteCar(@PathVariable String id) {
        carService.deleteCar(id);
        String response = "{\"success\": true, \"message\": Car has been deleted successfully.}";
        return response;
    }
}
Helmet answered 21/9, 2018 at 5:17 Comment(0)
T
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;
    }
Tunny answered 21/9, 2018 at 5:56 Comment(16)
i have Followed your second approach that handling exception globally by creating a class NoRecordFoundException class and creating a GlobalExceptionHandler class and finally added the throw new NoRecordFoundException(); in the controller.Helmet
Works well or any issue ??Tunny
but for this line @ResponseStatus(HttpStatus.NOT_FOUND) getting the error : HttpStatus can't be resolved to a variableHelmet
Can you check HttpStatus. For not foundTunny
Check what is imported in your package you might imported other than check #30649619Tunny
Or show me your global exception handler you might wrong imported for HttpStatus class when saw more optionsTunny
Should i create the method setMessage() in the errorResponse class. else i get the error message for this line : errorResponse.setMessage("No Record Found");Helmet
Yes getter and setter has to thereTunny
you are welcome, if you think my answer helped you to resolve your problem, please accept my answer.Tunny
This is the code for the internal error know like 500.Internal Server error @ExceptionHandler(Exception.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ResponseBody public final ErrorResponse handleAllExceptions(Exception ex, WebRequest request) { ErrorResponse errorResponse = new ErrorResponse(); errorResponse.setMessage("Internal Error"); return errorResponse; } But should i need to add any code in the MyController like we did for GET method.Helmet
Check my updated answer, yes you can handle it from global exception handler so no need to put try/catch in controller or service. no need to throw, it will landed in global if there will be any exception error.Tunny
what are all the possible exception will come for POST and PUT methods... <br/> - suppose if we give the same id in the body and try to post that request then the same request will be sent know. <br/> - suppose if we do modification in the data with same id then if we try to post that ID will gets updated rytHelmet
i think would be great if you post another question so thread can be specific to. if you will call save method with ID then it will be updated and if you will save body without id then it will created as new entry.Tunny
if my answer help you to resolve this issue then please accept my answer so other can take benefit of it.Tunny
@RequestMapping("/car/{id}") public ResponseEntity<?> getCar(@PathVariable String id) Here the ? indicates the Generic type Car ryt.Helmet
thats true and thats why you can response back your object, list, void, error response etc..Tunny
C
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.

Conformation answered 21/9, 2018 at 5:52 Comment(2)
After creating this what all changes should i do in my controller.Helmet
what are all the possible exception will come for POST and PUT methods... - suppose if we give the same id in the body and try to post that request then the same request will be sent know. - suppose if we do modification in the data with same id then if we try to post that ID will gets updated ryt.Helmet
P
0

if you don't want to implement ControllerAdvice and just need a quick Custom Exception you can use ResponseStatusException; according to https://www.baeldung.com/spring-response-status-exception

Pyramid answered 22/7, 2024 at 18:39 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.