I am trying to send a json file over REST Template. When I send it via POST man as MULTIPART_FORM_DATA, it works fine. The name I am supposed to give is specific (lets say aaa). Attached screenshot of POSTMAN. But when I try same in code as specified in another stackoverflow post, I get 415 Unsupported Media Type error as
org.springframework.web.client.HttpClientErrorException: 415 Unsupported Media Type
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:91) ~[spring-web-4.1.9.RELEASE.jar:4.1.9.RELEASE]
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:616) ~[spring-web-4.1.9.RELEASE.jar:4.1.9.RELEASE]
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:572) ~[spring-web-4.1.9.RELEASE.jar:4.1.9.RELEASE]
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:532) ~[spring-web-4.1.9.RELEASE.jar:4.1.9.RELEASE]
at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:332) ~[spring-web-4.1.9.RELEASE.jar:4.1.9.RELEASE]
at
Please do not mark it as duplicate as the specified answer did not work for me. Not sharing code as my code is exactly same as this except
requestParamerterMap.add("attachment", resource);
where as my code is
requestParamerterMap.add("aaa", resource);
After debugging it from the server side, looks like request is reaching out to server. I was able to see below error in the server side:
[{error=Unsupported Media Type, exception=org.springframework.web.HttpMediaTypeNotSupportedException, message=Content type 'application/octet-stream' not supported, status=415, timestamp=1532557180124}] as "application/json" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@74d4827a]
So, from the server side logs, I am not sure where the content type is getting added as application/octet-stream as I have set the content type as
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
Below is the code from server controller. Server side code uses Spring boot.
@RequestMapping(method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE,consumes = {"multipart/form-data"})
@ResponseBody
public MyResponse uploadPhoto(@RequestPart(value = "aaa", required = false) Optional<MyRequest> myRequest,
@RequestPart(value = "file", required = false) Optional<MultipartFile> file,
HttpServletRequest request) {
//some logic
return myResponse;
}
The server code has an interceptor where I can see my request has content type as multipart/form-data. It does not reach to RestController
When I debugged the server side code in 2 cases:
- POSTMAN request
- client code request
One thing I figured out that file iteam has content type as application/json when I post from POSTMAN and the content type was application/octet-stream when the request goes from client side code.
In my client side code, I am creating JSONObject as
JSONObject json = new JSONObject();
json.append("myKey", "myValue");
and convert it to byte array as
json.toString().getBytes("UTF-8")
then I have followed this . The difference in my code is, I am sending my JSONObject as byte stream as I can not create file (performance issues).
And I cant not send JSONObject as string as server is expecting multipart-form-data for both file and aaa
I have created the restTemplate as
public RestTemplate myRestTemplate() {
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setReadTimeout(HTTP_CLIENT_TIMEOUT);
requestFactory.setConnectTimeout(HTTP_CLIENT_TIMEOUT);
RestTemplate restTemplate = new RestTemplate(requestFactory);
List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
messageConverters.add(new FormHttpMessageConverter());
messageConverters.add(new StringHttpMessageConverter());
restTemplate.setMessageConverters(messageConverters);
return restTemplate;
Here is the client side code which calls the service:
public Optional<JSONObject> callService(byte[] multipartFile) {
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
InputStream stream = new ByteArrayInputStream(multipartFile);
MultipartByteArrayResource resource = new MultipartByteArrayResource(multipartFile,fileName);
body.add("aaa", resource);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
try {
response = restTemplate.postForObject(url, requestEntity , String.class);
} catch (Exception exception) {
LOG.error("Error", exception);
return Optional.empty();
}
}
public class MultipartInputStreamFileResource extends InputStreamResource {
private final String filename;
MultipartInputStreamFileResource(InputStream inputStream, String filename) {
super(inputStream);
this.filename = filename;
}
@Override
public String getFilename() {
return this.filename;
}
@Override
public long contentLength() throws IOException {
return -1; // we do not want to generally read the whole stream into memory ...
}
}
And same code works when I send file (note file and aaa are two different things though both are multipart/form-data in server side. file is just a file of any time (image/text/pdf) but aaa is json data file)
After debugging little bit more, what I observed is server side controller is expecting the file content to be json as Jackson try to deserialize that json to MyRequest object. When I send post from POSTMAN, it has the json content so working as expected but from the client side code, the content is byteArray, and its not getting deserialize to MyRequest object. Not sure how to fix this