I have an rest API in a Spring for generating and downloading a PDF file. The controller definitation is as follows -
@RequestMapping(
value = "/foo/bar/pdf",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
@ResponseBody
@Nullable
public ByteArrayResource downloadPdf(@RequestParam int userId) {
byte[] result = null;
ByteArrayResource byteArrayResource = null;
result = service.generatePdf(userId);
if (result != null) {
byteArrayResource = new ByteArrayResource(result);
}
return byteArrayResource;
}
I use Jackson for JSON handling JSON and have an Exception handler ControllerAdvice. The problem is when this API generates an exception and I return a custom exception class (contains message and one additional field).
As I already specified produces = MediaType.APPLICATION_OCTET_STREAM_VALUE
this custom class is also attempted to be converted to an octet stream by Spring, which it fails at and produces HttpMediaTypeNotAcceptableException: Could not find acceptable representation
.
I tried solutions on this Stackoverflow question, particularly this answer but it still fails. This solution, along with other changes suggests removing produces
part from @RequestMapping
but when I debugged into AbstractMessageConverterMethodProcessor.getProducibleMediaTypes
it only detects application/json as available response media type.
tl;dr How can I have this API return the file on success and correctly return custom exception class's JSON representation on error.
I had the same problem with similar code. I just removed the produces
attribute from my @PostMapping
and I was able to return the file or the json (when the api have some error):
@Override
@PostMapping
public ResponseEntity<InputStreamResource> generate(
@PathVariable long id
) {
Result result = service.find(id);
return ResponseEntity
.ok()
.cacheControl(CacheControl.noCache())
.contentLength(result.getSize())
.contentType(MediaType.parseMediaType(MediaType.APPLICATION_PDF_VALUE))
.body(new InputStreamResource(result.getFile()));
}
When some error occur, I had a @ExceptionHandler
to care of that:
@ExceptionHandler
public ResponseEntity<ApiErrorResponse> handleApiException(ApiException ex) {
ApiErrorResponse error = new ApiErrorResponse(ex);
return new ResponseEntity<>(error, ex.getHttpStatus());
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With