fastlearner
fastlearner

Reputation: 13

Spring boot RestTemplate - multipart/mixed

Have a REST API which only accepts content type multipart/mixed.

Trying to use restTemplate and generate REST request with content type multipart/mixed. If I comment setContentType restTemplate defaults to multipart/form-data.

setContentType(MediaType.parseMediaType("multipart/mixed"))

But no luck, any example how I can call API generating multipart/mixed request?

Maybe this helps

HttpHeaders publishHeaders = new HttpHeaders();
publishHeaders.set(HEADER_TABLEAU_AUTH, token);
publishHeaders.setContentType(MediaType.parseMediaType("multipart/mixed"));
String response;
LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
String payload = "<tsRequest>\n" +
        ............................
       "</tsRequest>";
map.add(TABLEAU_PAYLOAD_NAME, payload);
map.add("tableau_datasource", new FileSystemResource("/extract/test.tde"));
HttpEntity<LinkedMultiValueMap<String, Object>> entity = new HttpEntity<>(map, publishHeaders);
try {
response = restTemplate.postForObject(url + PUBLISH_DATASOURCE_SINGLE_CHUNK, entity, String.class, siteId);
} catch (RestClientException restEx) {
   log.error(....);
   throw restEx;
}

Upvotes: 1

Views: 4147

Answers (1)

Pytry
Pytry

Reputation: 6400

So, unfortunately, there really is no way to solve your problem with the current implementation of Springs RestTemplate from "spring-web-4.3.12.RELEASE.jar". It assumes in all cases that the only type of multipart data is "multipart/form-data:, and so it does not recoignize the multipart nature of your request.

org.springframework.http.converter.FormHttpMessageConverter: lines 247-272

@Override
@SuppressWarnings("unchecked")
public void write(MultiValueMap<String, ?> map, MediaType contentType, HttpOutputMessage outputMessage)
        throws IOException, HttpMessageNotWritableException {

    if (!isMultipart(map, contentType)) {
        writeForm((MultiValueMap<String, String>) map, contentType, outputMessage);
    }
    else {
        writeMultipart((MultiValueMap<String, Object>) map, outputMessage);
    }
}


private boolean isMultipart(MultiValueMap<String, ?> map, MediaType contentType) {
    if (contentType != null) {
        return MediaType.MULTIPART_FORM_DATA.includes(contentType);
    }
    for (String name : map.keySet()) {
        for (Object value : map.get(name)) {
            if (value != null && !(value instanceof String)) {
                return true;
            }
        }
    }
    return false;
}

If you look at the first part of the private method "isMultipart", you will see this:

    if (contentType != null) {
        return MediaType.MULTIPART_FORM_DATA.includes(contentType);
    }

It check to see if you have declared "multipart/form-data", but yours is "multipart/mixed", so it fails.

There are various other points at which it may also fail, but that's the root of the problem.

The only solution if you want to still use RestTemplate is to implement your own message converter that recognizes the desired media type, and add it to the templates message converters.

You could also write your own variation of RestTemplate by extending it, copy-paste and modify, or creating a client from scratch that uses something a bit more basic like apaches HttpClient (or even CORE java I suppose).

Upvotes: 2

Related Questions