Whenever my controller is throwing the exception, it is not not returning the response in json format.
It is giving Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
My controller is:
#RequestMapping(value = GENERATE_IMAGE, method = RequestMethod.GET, produces = MediaType.IMAGE_PNG_VALUE)
public byte[] get(#PathVariable("input") String input) throws IOException {
if (true) {
throw new BusinessValidationFailureException("sdfsdfsd");
}
ByteArrayInputStream inputStream = service.generate(input);
return ByteStreams.toByteArray(inputStream);
}
And my controller advice is:
#ControllerAdvice
public class WickesGlobalExceptionMapper extends ResponseEntityExceptionHandler {
#ExceptionHandler(BusinessValidationFailureException.class)
#ResponseBody
public ResponseEntity handleBusinessException(BusinessValidationFailureException ex, WebRequest request) {
ErrorResource error = new ErrorResource("InvalidRequest", ex.getMessage(), null);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return handleExceptionInternal(ex, error, headers, HttpStatus.UNPROCESSABLE_ENTITY, request);
}
}
I tried few other possibility but I got the same error page all the time.
I get below exception in the server:
org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:259) ~[spring-webmvc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor.handleReturnValue(HttpEntityMethodProcessor.java:203) ~[spring-webmvc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:81) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:132) ~[spring-webmvc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver.doResolveHandlerMethodException(ExceptionHandlerExceptionResolver.java:384) ~[spring-webmvc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.web.servlet.handler.AbstractHandlerMethodExceptionResolver.doResolveException(AbstractHandlerMethodExceptionResolver.java:59) [spring-webmvc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver.resolveException(AbstractHandlerExceptionResolver.java:136) [spring-webmvc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.web.servlet.handler.HandlerExceptionResolverComposite.resolveException(HandlerExceptionResolverComposite.java:74) [spring-webmvc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
You did not show the handleExceptionInternal method implementation, this does return an object?
Edit: I was wrong about the #RestControllerAdvice, removed it from the answer.
Let's assume you want to return an object of type ErrorData (this is not clear from your post). So you could use:
#ExceptionHandler(BusinessValidationFailureException.class)
#ResponseBody
public ResponseEntity<ErrorData> handleBusinessException(BusinessValidationFailureException e) {
ErrorData errorData = createYourErrorData();
return new ResponseEntity(errorData, HttpStatus.UNPROCESSABLE_ENTITY);
}
I just tried this and got the correct stataus code back together with the data object in JSON.
Since controller produces MediaType.IMAGE_PNG_VALUE, controlleradvice should also produce the same mediatype. I removed produces from requestmapping and set the content type in the response, and it worked.
#RequestMapping(value = GENERATE_BARCODE, method = RequestMethod.GET)
public ResponseEntity get(#PathVariable("input") String barcodeInput) throws IOException {
byte[] resonse = service.generate(barcodeInput);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_PNG);
return new ResponseEntity(resonse, headers, HttpStatus.OK);
}
Related
This is my controller:
#PostMapping(value = "/endpoint", produces = { APPLICATION_JSON_VALUE, APPLICATION_XML_VALUE})
#ResponseBody
public Result generateResult(#Valid #RequestBody Request request) throws JsonProcessingException {
Result result = new Result();
// some code here
return result;
}
and this is my Request class:
#Data
#NoArgsConstructor
public class Request {
#NotNull
private String name;
private String type = "application/json";
}
the controller produces the correct output based on the Accept header in the request sent by the client. However, I want to send no Accept header and only send the following request:
{
"name": "my name",
"type": "application/xml"
}
Then based on the type the correct format should be output. I tried to add HttpServletResponse response to the parameter list of the controller method and then set the content type like this:
response.setHeader(CONTENT_TYPE, request.geType());
but it always returns json. any idea what else I should do?
I think a standard Spring's ResponseEntity builder give you all needed variety:
return ResponseEntity
.ok(//any object for json structure)
.headers(//any header)
.build();
Instead .ok() you can you any other method (that's http status code)
or
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("MyHeader", "MyValue");
return new ResponseEntity<String>("Hello World", responseHeaders, HttpStatus.OK);
based on the comments I post this answer which worked for me. I changed my controller method like this:
#PostMapping(value = "/endpoint", produces = { APPLICATION_JSON_VALUE,
APPLICATION_XML_VALUE})
#ResponseBody
public ResponseEntity<Result> generateResult(#Valid #RequestBody Request request)
throws JsonProcessingException {
Result result = new Result();
// some code here
return ResponseEntity.accepted()
.headers(headers)
.body(result);
}
Sorry, i am newbie on java web development.
I got some task to fetch user profile picture from 3rd party company via HTTP rest(GET method). Their api only can be accessed using session id on the header parameter and the api will return some byte[] array looks like ’ÑÒBRSb¢ÂáTr²ñ#‚4“â3C etc.
How to handle rest response with content type image/jpg in Rest Template?
I do my best like this
private RestTemplate restTemplate;
public byte[] getProfilePic(){
String canonicalPath = "http://dockertest/bankingapp/customer/profpicFile";
String sessionId= "MTQ4NzE5Mz...etc";
HttpEntity<byte[]> request = new HttpEntity<byte[]>(null, getHeaders(true, "GET", null, canonicalPath, sessionId));
//getHeaders() will return HttpHeaders with those parameter
ResponseEntity<byte[]> response = null;
try {
response = this.restTemplate.exchange(uri, HttpMethod.GET, request, byte[].class);
} catch( HttpServerErrorException hse ){
throw hse;
}
return response;
}
This code will return an error
org.springframework.web.client.RestClientException: Could not extract
response: no suitable HttpMessageConverter found for response type
[[B] and content type [image/jpg]
Any suggestion or help will be appreciated!
Thank you
Update
Using stackoveflower suggestions i can manage to solve this.
private RestTemplate restTemplate;
public byte[] getProfilePic(){
String canonicalPath = "/mobile/customer/profpicFile";
String sessionId= "MTQ4NzE5Mz...etc";
HttpEntity<byte[]> request = new HttpEntity<byte[]>(null, getHeaders(true, "GET", null, canonicalPath, sessionId));
//getHeaders() will return HttpHeaders with those parameter
ResponseEntity<byte[]> response = null;
try {
restTemplate.getMessageConverters().add(new ByteArrayHttpMessageConverter());
response = this.restTemplate.exchange(uri, HttpMethod.GET, request, byte[].class).getBody();
return response;
} catch( HttpServerErrorException hse ){
throw hse;
}
return null;
}
Note about HttpMessageConverter, instead using list, i can directly add a ByteArrayHttpMessageConverter()
As said I guess you must use the right messageconverter
I would do in this way:
private RestTemplate restTemplate;
public byte[] getProfilePic(){
String canonicalPath = "http://dockertest/bankingapp/customer/profpicFile";
String sessionId= "MTQ4NzE5Mz...etc";
List<HttpMessageConverter> converters = new ArrayList<>(1);
converters.add(new ByteArrayHttpMessageConverter());
restTemplate.setMessageConverters(converters);
HttpEntity<byte[]> request = new HttpEntity<byte[]>(null, getHeaders(true, "GET", null, canonicalPath, sessionId));
//getHeaders() will return HttpHeaders with those parameter
ResponseEntity<byte[]> response = null;
try {
response = this.restTemplate.exchange(uri, HttpMethod.GET, request, byte[].class);
} catch( HttpServerErrorException hse ){
throw hse;
}
return response;
}
More information can be found here: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html#setMessageConverters-java.util.List- and here https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/converter/HttpMessageConverter.html and here https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/converter/ByteArrayHttpMessageConverter.html
Thank you very much,this problem takes up my a lot of time. Now,it was resolved.
following:
#Configuration
#Slf4j
public class RestTemplateConfiguration implements ApplicationContextAware {
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
RestTemplate restTemplate = (RestTemplate) applicationContext.getBean("restTemplate");
restTemplate.getMessageConverters().add(new ByteArrayHttpMessageConverter());
restTemplate.setUriTemplateHandler(new GetUriTemplateHandler());
}
}
I´m having some issues when returning some errors from a rest WebService.
Making a request with the header {"Accept":"application/octet-stream"}
(the service returns a document ResponseEntity<InputStreamResource> if all the process goes well).
When all the process goes well the document is downloaded fine, but when an error is occurred and the code jumps to the #ControllerAdvice and tries to return a JSON error. Here comes the problem, when trying to return the JSON springs crashes:
org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation
Here is a example of some code:
Controller
#RequestMapping(value = "/test", method = RequestMethod.GET, produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_OCTET_STREAM_VALUE })
public ResponseEntity<CustomError> test() throws Exception {
throw new Exception();
}
ControllerAdvice
#ControllerAdvice
public class ExceptionHandlerAdvice {
private static final Logger logger = LogManager.getLogger(ExceptionHandlerAdvice.class);
#ExceptionHandler({Exception.class,Throwable.class})
#ResponseBody
public ResponseEntity<CustomError> handleUnhandledException(Exception exception) {
CustomError error = new CustomError(exception.getMessage());
return new ResponseEntity<CustomError>(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
CustomError:
public class CustomError {
private String errorDescription;
public CustomError(String errorDescription) {
super();
this.errorDescription = errorDescription;
}
public String getErrorDescription() {
return errorDescription;
}
public void setErrorDescription(String errorDescription) {
this.errorDescription = errorDescription;
}
}
I´ve also tried returning new headers on #controllerAdvice
#ExceptionHandler({Exception.class,Throwable.class})
#ResponseBody
public ResponseEntity<CustomError> handleUnhandledException(Exception exception) {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
CustomError error = new CustomError(exception.getMessage());
return new ResponseEntity<CustomError>(error,headers, HttpStatus.INTERNAL_SERVER_ERROR);
}
Any idea how can I make this work or ignore Accept header on response?
It´s possible?
Thanks in advance
This exception means your response type not match with your request header. If you are expecting JSON/Stream to be returned, your request header should be {"Accept":"application/octet-stream,application/json"}.
I have a spring controller that accepts a class named FileUploadBean on POST. The controller method looks like that:
First Controller:
#RequestMapping(value = "/upload", method = RequestMethod.POST)
#ResponseBody
public ResponseEntity<byte[]> uploadFile(final FileUploadBean fileUploadBean) throws IOException {
// Some code that works fine here
}
One of the FileUploadBean properties is of type MultipartFile.
Now, I'm trying to add some sort of wrapper controller (that will run on another server) that also accepts FileUploadBean and just forwards the request to the first controller:
Second (wrapper) Controller:
#RequestMapping(value="/upload", method = RequestMethod.POST)
#ResponseBody
public ResponseEntity<byte[]> uploadImage(final FileUploadBean fileUploadBean) throws IOException {
ResponseEntity<byte[]> response = restTemplate.postForEntity([first controller url here], fileUploadBean, byte[].class);
return response;
}
When I'm sending the request to the first controller I get:
org.springframework.http.converter.HttpMessageNotWritableException:
Could not write JSON: No serializer found for class
java.io.FileDescriptor and no properties discovered to create
BeanSerializer (to avoid exception, disable
SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain:
com.outbrain.images.beans.FileUploadBean["file"]->org.springframework.web.multipart.commons.CommonsMultipartFile["fileItem"]->org.apache.commons.fileupload.disk.DiskFileItem["inputStream"]->java.io.FileInputStream["fd"]);
nested exception is
com.fasterxml.jackson.databind.JsonMappingException: No serializer
found for class java.io.FileDescriptor and no properties discovered to
create BeanSerializer (to avoid exception, disable
SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain:
com.outbrain.images.beans.FileUploadBean["file"]->org.springframework.web.multipart.commons.CommonsMultipartFile["fileItem"]->org.apache.commons.fileupload.disk.DiskFileItem["inputStream"]->java.io.FileInputStream["fd"])
at org.springframework.http.converter.json.MappingJackson2HttpMessageConverter.writeInternal
How can I make this request work?
Well, after some struggling this is how I solved it. That's what I did in the second controller:
#RequestMapping(value = "/upload", method = RequestMethod.POST)
public #ResponseBody
ResponseEntity<byte[]> uploadImage(final FileUploadBean fileUploadBean) throws Exception {
File file = null;
try {
final MultiValueMap<String, Object> requestParts = new LinkedMultiValueMap<>();
final String tmpImageFileName = IMAGE_TMP_DIR + fileUploadBean.getFile().getOriginalFilename();
file = new File(tmpImageFileName);
fileUploadBean.getFile().transferTo(file);
requestParts.add("file", new FileSystemResource(tmpImageFileName));
HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type", "multipart/form-data"); // Sending it like the client-form sends it
ResponseEntity<byte[]> response = restTemplate.exchange(ImageUrlUtils.getUploadUrl(), HttpMethod.POST, new HttpEntity<>(requestParts, headers),
byte[].class);
return new ResponseEntity<>(response.getBody(), response.getStatusCode());
} catch (Exception ex) {
return new ResponseEntity<>((ex.getMessage).getBytes("UTF-8"),
HttpStatus.INTERNAL_SERVER_ERROR);
} finally {
if (file != null && file.exists()) {
file.delete();
}
}
}
I debug previous answer, and found this solution without save file to file system
#PostMapping(value = "/upload")
public ResponseEntity<Object> upload(MultipartHttpServletRequest request) throws Exception {
final MultiValueMap<String, Object> requestParts = new LinkedMultiValueMap<>();
request.getParameterMap().forEach((name, value) -> requestParts.addAll(name, asList(value)));
request.getMultiFileMap().forEach((name, value) -> {
List<Resource> resources = value.stream().map(MultipartFile::getResource).collect(toList());
requestParts.addAll(name, resources);
});
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(requestParts, request.getRequestHeaders());
return restTemplate.exchange(ImageUrlUtils.getUploadUrl() + "?" + request.getQueryString(),
request.getRequestMethod(), requestEntity, Object.class);
}
I would like to set the produces = text/plain to produces = application/json when I encounter an error.
#RequestMapping(value = "/v0.1/content/body", method = RequestMethod.GET, produces = "text/plain")
#ResponseBody
public Object getBody(#RequestParam(value = "pageid") final List<String> pageid, #RequestParam(value = "test") final String test) {
if (!UUIDUtil.isValid(pageid)) {
Map map = new HashMap();
map.put("reason", "bad pageId");
map.put("pageId", pageId);
map.put("test", test);
return new ResponseEntity<Object>(map, HttpStatus.BAD_REQUEST);
}
return "hello";
}
The problem with this code is that it doesn't print the error as json when I send an invalid pageId. It gives me a HTTP 406 error Not acceptable, because it expects to produce text/plain but I didn't return a String.
The cleanest way to handle errors is to use #ExceptionHandler:
#ExceptionHandler(EntityNotFoundException.class) //Made up that exception
#ResponseBody
#ResponseStatus(value = HttpStatus.NOT_FOUND)
public ErrorObject handleException(Exception e) {
return new ErrorObject(e.getMessage());
}
Then assuming you've configured your resolvers properly and put the right JSON serialization library in the classpath, the instance of ErrorObject will be returned to the client as a JSON response.
Of course you can set up multiple #ExceptionHandler methods as needed.