6

In Spring Boot, I create custom exception class with specific status code, and I call it to throw exception with code: 100 and message: "No have content" at controller, but output still returns "status": 500 and "error": "Internal Server Error"

AppException.java

public class AppException extends RuntimeException {

    private static final long serialVersionUID = 1L;

    private final Integer code;

    public AppException(Integer code, String message) {
        super(message);
        this.code = code;
    }

    public Integer getCode() {
        return code;
    }
}

UserController.java

@RestController
@RequestMapping("/api/user")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping()
    public ApiResponseDto getAllUsers(Pageable pageable) {
        Page<User> users = userService.getAllUsers(pageable);

        if (users.getSize() < 0) {
            throw new AppException(100, "No have content");
        }

        return new ApiResponseDto(HttpStatus.OK.value(), users);
    }

Actual Output:

{
    "timestamp": 1550987372934,
    "status": 500,
    "error": "Internal Server Error",
    "exception": "com.app.core.exception.AppException",
    "message": "No have content",
    "path": "/api/user"
}

My expectation:

{
    "timestamp": 1550987372934,
    "status": 100,
    "error": "No have content",
    "exception": "com.app.core.exception.AppException",
    "message": "No have content",
    "path": "/api/user"
}

3 Answers 3

6

In case you want to have global exception handling for your API, and prefer to have custom error responses, you can add @ControllerAdvice:

@ControllerAdvice
public class ApiExceptionHandler {

    @ExceptionHandler({ ApiException.class })
    protected ResponseEntity<ApiErrorResponse> handleApiException(ApiException ex) {
        return new ResponseEntity<>(new ApiErrorResponse(ex.getStatus(), ex.getMessage(), Instant.now()), ex.getStatus());
    }
}

// you can put any information you want in ApiErrorResponse 
public class ApiErrorResponse {

    private final HttpStatus status;
    private final String message;
    private final Instant timestamp;

    public ApiError(HttpStatus status, String message, Instant timestamp) {
        this.status= status;
        this.message = message;
        this.timestamp = timestamp;
    }

    public HttpStatus getStatus() { 
        return this.status; 
    }

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

    public Instant getTimestamp() {
        return this.timestamp;
    }
}

// your custom ApiException class
public class ApiException extends RuntimeException {

    private final HttpStatus status;

    public ApiException(HttpStatus status, String message) {
        super(message);
        this.status = status;
    }

    public HttpStatus getStatus() {
        return this.status;
    }
}
Sign up to request clarification or add additional context in comments.

5 Comments

Thank you, but throw new AppException(100, "No have content"); is example. Because, I want to use AppException class for many my status code in project
@Tony I updated the answer in case you want to have global exception handling for your API, and prefer to have custom error responses.
thanks, but I want to throw exception at anywhere service class, java class, ..., not return for controller. btw, using @ControllerAdvice it also not return exactly status code I put for ApiException(Integer code, String message). Can you suggest me other way?
@Tony Exception could be thrown anywhere in your code. Also use HttpStatus instead of Integer inside ApiException.
Why are there 2 public classes in the same file?
3

If you need a limited number of different error-messages or you want to reuse the same one several times, then that's all you need:

@ResponseStatus(value = HttpStatus.CONTINUE, reason = "No have content")
public class AppException extends RuntimeException {
    private static final long serialVersionUID = 1L;
}

No need of any extra classes and handlers. Your code will be clear and simple.

You can simply raise it like this:

throw new AppException();

Comments

1

There are multiple ways to achieve this:

  1. ExceptionHandler

    You can add a @ExceptionHandler annotated method in your controller:

    @ExceptionHandler({ CustomException1.class, CustomException2.class })
    public void handleException() {
    //
    }
    
  2. HandlerExceptionResolver

    You can also implement a custom resolver to intercept all exceptions and handle them globally by overriding the doResolveException method

More detail on the above two approaches can be found here: https://www.baeldung.com/exception-handling-for-rest-with-spring

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.