Exception handling in StreamingResponseBody

Viewed 1689

I'm trying to catch an exception thrown in my implementation of StreamingResponseBody, I can see the exception being thrown inside the class however the thrown exception isn't visible to the method body or my Controller Advice. So none of my handling seems to work, just interested to know which is the correct way to handle exceptions in this case.

@GetMapping(path = "/test", produces = "application/json")
public StreamingResponseBody test(@RequestParam(value = "var1") final String test)
        throws IOException{

    return new StreamingResponseBody() {

        @Override
        public void writeTo(final OutputStream outputStream) throws IOException{
            try {
                  // Some operations..
            } catch (final SomeCustomException e) {
                throw new IOException(e);
            }
        }
    };
}

I would expect my ControllerAdvice to return an ResponseEntity with a Http Status of 500.

1 Answers

The best way I discovered to handle errors/exceptions in the web environment is to create your custom exception with the disabled stack trace, and handle it with @ControllerAdvice.

import lombok.Getter;
import org.springframework.http.HttpStatus;

public class MyException extends RuntimeException {

    @Getter private HttpStatus httpStatus;

    public MyException(String message) {
        this(message, HttpStatus.INTERNAL_SERVER_ERROR);
    }

    public MyException(String message, HttpStatus status) {
        super(message, null, false, false);
        this.httpStatus = status;
    }
}

And then handle it in @ControllerAdvice like this:

@ExceptionHandler(MyException.class)
public ResponseEntity handleMyException(MyException exception) {
    return ResponseEntity.status(exception.getHttpStatus()).body(
            ErrorDTO.builder()
                    .message(exception.getMessage())
                    .description(exception.getHttpStatus().getReasonPhrase())
                    .build());
}

where ErrorDTO is just a simple DTO with two fields:

@Value
@Builder
public class ErrorDTO {

    private final String message;
    private final String description;

}
Related