Skip to content

Instantly share code, notes, and snippets.

@jonikarppinen
Last active November 17, 2021 11:49
Show Gist options
  • Save jonikarppinen/6ade2554946df21db0a6 to your computer and use it in GitHub Desktop.
Save jonikarppinen/6ade2554946df21db0a6 to your computer and use it in GitHub Desktop.
Example of using ExceptionHandler in Spring Boot: a controller method that returns either binary data or error JSON
package com.company.project.controllers;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.Random;
/**
* Example of a Spring Boot controller method that can return either:
* - 200 OK with binary data (application/pdf)
* - 503 Service Unavailable with JSON error message
*
* (Everything defined as static nested classes just for readability of this example.)
*
* @author Joni Karppinen
* @since 2015-10-28
*/
@RestController
public class PdfOrErrorController {
/**
* Successful case, returns byte[] (fake PDF data)
* Content type will be application/pdf
*/
@RequestMapping(value = "/test", method = RequestMethod.GET)
public ResponseEntity<byte[]> test() {
// Set Content-Type header (+ content disposition, etc, if you want)
// (Not using "produces", because that depends on request's Accept header including
// "application/pdf" and otherwise returns 406 Not Acceptable.)
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType("application/pdf"));
String filename = "output.pdf";
headers.setContentDispositionFormData(filename, filename);
return new ResponseEntity<>(getDataOrThrowException(), headers, HttpStatus.OK);
}
/**
* Error case, returns ErrorResponse which Spring automatically converts to JSON (using Jackson)
* Content type will be application/json
*/
@ExceptionHandler(OriginalExceptionFromAnotherApi.class)
@ResponseStatus(HttpStatus.SERVICE_UNAVAILABLE)
public ErrorResponse handle(OriginalExceptionFromAnotherApi e) {
return new ErrorResponse(e.getMessage()); // use message from the original exception
}
private Random random = new Random();
/**
* Fake "service layer"
*/
private byte[] getDataOrThrowException() {
if (random.nextBoolean()) {
return getBinaryData();
}
else {
throw new OriginalExceptionFromAnotherApi("Failed because the other API is down!");
}
}
private byte[] getBinaryData() {
byte[] b = new byte[20];
random.nextBytes(b);
return b;
}
/**
* Defines the JSON output format of error responses
*/
private static class ErrorResponse {
public String message;
public ErrorResponse(String message) {
this.message = message;
}
}
private static class OriginalExceptionFromAnotherApi extends RuntimeException {
public OriginalExceptionFromAnotherApi(String message) {
super(message);
}
}
}
@rem-ebsco
Copy link

I tried this and it is not returning JSON, just the default Whitelabel page that says I haven't made an explicit mapping for /error. In fact, it does exactly the same thing as if I had used response.sendError instead. How do I get rid of the Whitelabel page and return JSON?

@cesar-lp
Copy link

I found that adding this two lines in application.properties it doesn't redirect me anymore to the /error page

spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment