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
Finally I solved this issue. As mentioned in question, having different content type of multipart file while sending request from POSTMAN vs code is where I began with. I will explain in details if anyone has any questions.
public Optional<JSONObject> save(byte[] multipartFile, String fileName) {
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
Resource content = new MultipartByteArrayResource(multipartFile , fileName);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Resource> requestEntityBody = new HttpEntity<Resource>(content, headers);
body.add("aaa", requestEntityBody);
String result = "";
JSONParser parser = new JSONParser();
JSONObject json = null;
HttpHeaders requestHeaders = new HttpHeaders();
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, requestHeaders);
ResponseEntity<String> response = null;
try {
RestTemplate restTemplate = customizeRestTemplate(); //I have defined this in different config file in my actual code
response = restTemplate.exchange(url , HttpMethod.POST , requestEntity , String.class);
result = (response != null && response.getBody() != null) ? response.getBody().toString() : result;
json = (JSONObject) parser.parse(result);
LOG.info( "Response:", response );
} catch (Exception exception) {
LOG.error("Error , exception);
return Optional.empty();
}
return Optional.ofNullable(json);
}
public class MultipartByteArrayResource extends ByteArrayResource{
private String fileName;
public MultipartByteArrayResource(byte[] byteArray , String filename) {
super(byteArray);
this.fileName = filename;
}
public String getFilename() {
return fileName;
}
public void setFilename(String fileName) {
this.fileName= fileName;
}
}
public RestTemplate customizeRestTemplate() {
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setReadTimeout(10000);
requestFactory.setConnectTimeout(10000);
RestTemplate restTemplate = new RestTemplate(requestFactory);
List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
messageConverters.add(new FormHttpMessageConverter());
messageConverters.add(new StringHttpMessageConverter());
restTemplate.setMessageConverters(messageConverters);
return restTemplate;
}
}
The server-side exception is produced by org.springframework.http.converter.json.MappingJackson2HttpMessageConverter. Jackson is a JSON library and MessageConverter are used by Spring to format requests and responses.
Can it be that the client sends an "Accept: application/octet-stream" while the server has a #Produces(APPLICATION_JSON) annotation? That would mean that the server processes the request and only has problems sending the response. You could add some log.info() statements in the server to verify this.
I'm using RestTemplate and SpringBoot 2.0.
I have this class which represents a custom JSON response to rest calls.
MyCustomResponse<T> {
private T content;
public T getContent() {
return content;
}
}
The code snippet below is a example of use:
String LOCALHOST = "http://localhost:8900";
final HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.ACCEPT, "application/json");
String url = String.format("%s/ticket/%s", LOCALHOST, protocol);
final HttpEntity<Ticket> request = new HttpEntity<>(headers);
This works fine:
ResponseEntity<MyCustomResponse> response =
testRestTemplate.getForEntity(url, RespostaPadrao.class);
But it's not what I need, because getContent returns a object that looks like:
Map< Map < String, Map < String, Map < String, Map < String, Integer >>>>>
and because I want to test a Ticket object instead.
In this line, can I use reflection to parametrize the response or this is impossible?
ResponseEntity<MyCustomResponse> response =
testRestTemplate.getForEntity(url, MyCustomResponse.class);
I know how to fix it with ResponseEntity<String> and parse the JSON to my Ticket. But what I really need is know if is possible delegate this task to RestTemplate or not.
Thanks!
i currently use Google's GSON library to serialize/deserialize rest service responses.
But i have a little problem. My response object has T response attribute.
public class IninalResponse<T> {
private int httpCode;
private String description;
private T response;
private HashMap<String,String> validationErrors;
...
}
I would like to get response attribute according to object type which i specified. At this example i specified with GetAccessTokenResponse to deserialize T response attribute in the piece of code below.
public IninalResponse getAccessToken(String apikey) {
String path = "https://sandbox-api.ininal.com/v2/oauth/accesstoken";
return doPostIninal(apikey,path,null,GetAccessTokenResponse.class);
}
GSON library successfully deserializes IninalResponse object except for T response field. Gson deserializes it as LinkedTreeMap typed object.
public <T,V> IninalResponse doPostIninal(String apikey, String path,V requestBody, T response) {
RestTemplate template = restClient.getRestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.AUTHORIZATION,apikey);
headers.add(HttpHeaders.DATE, "");
headers.add(HttpHeaders.CONTENT_TYPE, "application/json");
HttpEntity<?> request = new HttpEntity<Object>(requestBody,headers);
ResponseEntity<String> accessTokenResponse = restClient.getRestTemplate().postForEntity(path,request,String.class);
IninalResponse<T> responseBody = new IninalResponse<T>();
responseBody = new Gson().fromJson(accessTokenResponse.getBody(),responseBody.getClass());
System.out.println(accessTokenResponse);
return responseBody;
}
Still i have no idea why gson could not deserialize ? What exactly am i missing ?
Due to Java's type erasure, you need to make a trick to serialize/deserialize generic types:
Type fooType = new TypeToken<IninalResponse<TheType>>() {}.getType();
gson.fromJson(accessTokenResponse.getBody(), fooType);
where TheType is the type you passed in during serialization (String I suppose).
Serialization goes as this:
Type fooType = new TypeToken<IninalResponse<String>>() {}.getType(); // I assume it was a String here.
gson.toJson(someString, fooType);
I'm trying to retrieve some data from a REST service using spring for Android.
However I'm running into problems. I'm also using Robospice - and as such have a method like so:
public FunkyThingsList loadDataFromNetwork() throws Exception {
String baseURI =context.getResources().getString(R.string.baseWebServiceURI);
String uri = baseURI + "/FunkyThings/date/" + dateToLookUp.toString("yyyy-MM-dd");
RestTemplate restTemplate = getRestTemplate();
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
headers.setAccept( Arrays.asList(MediaType.APPLICATION_JSON));
HttpAuthentication authHeader = new HttpBasicAuthentication(username, password);
headers.setAuthorization(authHeader);
// Create the request body as a MultiValueMap
MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
HttpMessageConverter<String> stringConverter = new StringHttpMessageConverter();
FormHttpMessageConverter formConverter = new FormHttpMessageConverter();
List<HttpMessageConverter<?>> msgConverters = restTemplate.getMessageConverters();
msgConverters.add(formConverter);
msgConverters.add(stringConverter);
restTemplate.setMessageConverters(msgConverters);
HttpEntity<?> httpEntity = new HttpEntity<Object>(map, headers);
final ResponseEntity<FunkyThingsList> responseEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity,FunkyThingsList.class);
return responseEntity.getBody();
}
Unfortunately this isn't working. I'm getting the following exception thrown:
org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [com.MyProject.DataClassPojos.RoboSpiceArrayLists.FunkyThingsList] and content type [application/json;charset=utf-8]
Now based on my Googling I get the feeling I need to add a message converter. I'm just not sure which message converter I need, or where I add it?
For the default JSON HttpMessageConverter, you'll need to add either Jackson 1 or Jackson 2 to your classpath.
Otherwise, you can add some other JSON library and write your own HttpMessageConverter which can do the deserialization. You add it to the RestTemplate. You can either use the constructor or this method.
If you are following the Spring for Android tutorial and you get the same error - this might be of help:
In your MainActivity.java:
...
RestTemplate restTemplate = new RestTemplate();
MappingJacksonHttpMessageConverter converter = new
MappingJacksonHttpMessageConverter();
converter.setSupportedMediaTypes(Collections.singletonList(MediaType.TEXT_HTML));
restTemplate.getMessageConverters().add(converter);
Use the converter in the call and configure it to use as a Media Type the TEXT_HTML, then use the instance of the converter.
Also the tutorial is a bit outdated so use the latest versions as suggested here in your build.gradle:
dependencies{
//Spring Framework for REST calls and Jackson for JSON processing
compile 'org.springframework.android:spring-android-rest-template:2.0.0.M3'
compile 'com.fasterxml.jackson.core:jackson-databind:2.4.1.3'
}
repositories {
maven {
url 'https://repo.spring.io/libs-milestone'
}
}
I didn't find any example how to solve my problem, so I want to ask you for help. I can't simply send POST request using RestTemplate object in JSON
Every time I get:
org.springframework.web.client.HttpClientErrorException: 415 Unsupported Media Type
I use RestTemplate in this way:
...
restTemplate = new RestTemplate();
List<HttpMessageConverter<?>> list = new ArrayList<HttpMessageConverter<?>>();
list.add(new MappingJacksonHttpMessageConverter());
restTemplate.setMessageConverters(list);
...
Payment payment= new Payment("Aa4bhs");
Payment res = restTemplate.postForObject("http://localhost:8080/aurest/rest/payment", payment, Payment.class);
What is my fault?
This technique worked for me:
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<String>(requestJson, headers);
ResponseEntity<String> response = restTemplate.put(url, entity);
I ran across this problem when attempting to debug a REST endpoint. Here is a basic example using Spring's RestTemplate class to make a POST request that I used. It took me quite a bit of a long time to piece together code from different places to get a working version.
RestTemplate restTemplate = new RestTemplate();
String url = "endpoint url";
String requestJson = "{\"queriedQuestion\":\"Is there pain in your hand?\"}";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<String>(requestJson,headers);
String answer = restTemplate.postForObject(url, entity, String.class);
System.out.println(answer);
The particular JSON parser my rest endpoint was using needed double quotes around field names so that's why I've escaped the double quotes in my requestJson String.
I've been using rest template with JSONObjects as follow:
// create request body
JSONObject request = new JSONObject();
request.put("username", name);
request.put("password", password);
// set headers
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<String>(request.toString(), headers);
// send request and parse result
ResponseEntity<String> loginResponse = restTemplate
.exchange(urlString, HttpMethod.POST, entity, String.class);
if (loginResponse.getStatusCode() == HttpStatus.OK) {
JSONObject userJson = new JSONObject(loginResponse.getBody());
} else if (loginResponse.getStatusCode() == HttpStatus.UNAUTHORIZED) {
// nono... bad credentials
}
As specified here I guess you need to add a messageConverter for MappingJacksonHttpMessageConverter
I'm doing in this way and it works .
HttpHeaders headers = createHttpHeaders(map);
public HttpHeaders createHttpHeaders(Map<String, String> map)
{
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
for (Entry<String, String> entry : map.entrySet()) {
headers.add(entry.getKey(),entry.getValue());
}
return headers;
}
// Pass headers here
String requestJson = "{ // Construct your JSON here }";
logger.info("Request JSON ="+requestJson);
HttpEntity<String> entity = new HttpEntity<String>(requestJson, headers);
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
logger.info("Result - status ("+ response.getStatusCode() + ") has body: " + response.hasBody());
logger.info("Response ="+response.getBody());
Hope this helps
If you are using Spring 3.0, an easy way to avoid the org.springframework.web.client.HttpClientErrorException: 415 Unsupported Media Type exception, is to include the jackson jar files in your classpath, and use mvc:annotation-driven config element. As specified here.
I was pulling my hair out trying to figure out why the mvc-ajax app worked without any special config for the MappingJacksonHttpMessageConverter. If you read the article I linked above closely:
Underneath the covers, Spring MVC
delegates to a HttpMessageConverter to
perform the serialization. In this
case, Spring MVC invokes a
MappingJacksonHttpMessageConverter
built on the Jackson JSON processor.
This implementation is enabled
automatically when you use the
mvc:annotation-driven configuration
element with Jackson present in your
classpath.
The "415 Unsupported Media Type" error is telling you that the server will not accept your POST request. Your request is absolutely fine, it's the server that's mis-configured.
MappingJacksonHttpMessageConverter will automatically set the request content-type header to application/json, and my guess is that your server is rejecting that. You haven't told us anything about your server setup, though, so I can't really advise you on that.
Why work harder than you have to? postForEntity accepts a simple Map object as input. The following works fine for me while writing tests for a given REST endpoint in Spring. I believe it's the simplest possible way of making a JSON POST request in Spring:
#Test
public void shouldLoginSuccessfully() {
// 'restTemplate' below has been #Autowired prior to this
Map map = new HashMap<String, String>();
map.put("username", "bob123");
map.put("password", "myP#ssw0rd");
ResponseEntity<Void> resp = restTemplate.postForEntity(
"http://localhost:8000/login",
map,
Void.class);
assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK);
}
I was getting this problem and I'm using Spring's RestTemplate on the client and Spring Web on the server. Both APIs have very poor error reporting, making them extremely difficult to develop with.
After many hours of trying all sorts of experiments I figured out that the issue was being caused by passing in a null reference for the POST body instead of the expected List. I presume that RestTemplate cannot determine the content-type from a null object, but doesn't complain about it. After adding the correct headers, I started getting a different server-side exception in Spring before entering my service method.
The fix was to pass in an empty List from the client instead of null. No headers are required since the default content-type is used for non-null objects.
This code is working for me;
RestTemplate restTemplate = new RestTemplate();
Payment payment = new Payment("Aa4bhs");
MultiValueMap<String, Object> map = new LinkedMultiValueMap<String, Object>();
map.add("payment", payment);
HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<MultiValueMap<String, Object>>(map, headerObject);
Payment res = restTemplate.postForObject(url, httpEntity, Payment.class);
If you dont want to process response
private RestTemplate restTemplate = new RestTemplate();
restTemplate.postForObject(serviceURL, request, Void.class);
If you need response to process
String result = restTemplate.postForObject(url, entity, String.class);
I tried as following in spring boot:
ParameterizedTypeReference<Map<String, Object>> typeRef = new ParameterizedTypeReference<Map<String, Object>>() {};
public Map<String, Object> processResponse(String urlendpoint)
{
try{
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
//reqobj
JSONObject request = new JSONObject();
request.put("username", name);
//Or Hashmap
Map<String, Object> reqbody = new HashMap<>();
reqbody.put("username",username);
Gson gson = new Gson();//mvn plugin to convert map to String
HttpEntity<String> entity = new HttpEntity<>( gson.toJson(reqbody), headers);
ResponseEntity<Map<String, Object>> response = resttemplate.exchange(urlendpoint, HttpMethod.POST, entity, typeRef);//example of post req with json as request payload
if(Integer.parseInt(response.getStatusCode().toString()) == HttpURLConnection.HTTP_OK)
{
Map<String, Object> responsedetails = response.getBody();
System.out.println(responsedetails);//whole json response as map object
return responsedetails;
}
} catch (Exception e) {
// TODO: handle exception
System.err.println(e);
}
return null;
}
For me error occurred with this setup:
AndroidAnnotations
Spring Android RestTemplate Module
and ...
GsonHttpMessageConverter
Android annotations has some problems with this converted to generate POST request without parameter. Simply parameter new Object() solved it for me.
If you don't want to map the JSON by yourself, you can do it as follows:
RestTemplate restTemplate = new RestTemplate();
restTemplate.setMessageConverters(Arrays.asList(new MappingJackson2HttpMessageConverter()));
ResponseEntity<String> result = restTemplate.postForEntity(uri, yourObject, String.class);
You can make request as a JSON object
JSONObject request = new JSONObject();
request.put("name","abc");
ResponseEntity<JSONObject> response =restTemplate.postForEntity(append_url,request,JSONObject.class); `enter code here`