0

Can we send MultipartFile inside a Custom Request Object in a Rest Template call? Similarly, can we receive a MutlipartFile inside a Custom Response Object returned from a Rest call made through the Rest Template?

Basically, we need to send other essential attributes along with a File Upload and receive few attributes along with a File Download.

Is this possible through a Spring Rest Template?

Below is the Code,

public class UploadRequest {    
    private Long checkSum;    
    private MultiPartFile fileContents; 
    //setters and getters  
}  

We receive the MultipartFile from a controller end point, we just relay it to another endpoint using the below is the Rest template call,

HttpHeaders headers = new HttpHeaders();  
headers.setContentType("mutipart/form-data");  
  
MultiValueMap<String, Object> map = new MultiValueMap<>();  
map.add("uploadRequest", uploadRequest);  
  
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(map, headers);  
  
ResponseEntity<UploadResponse> responseEntity = restTemplate.postForEntity(uploadUrl, requestEntity, UploadResponse.class);  

it results in the below exception,

com.fasterxml.jackson.databind.exc.InvalidDefinitionException No Serializer for class java.io.FileDescriptor

and

no properties discovered to create BeanSerializer
omar jayed
  • 850
  • 5
  • 16
Sabari
  • 127
  • 1
  • 13

2 Answers2

1

Yes, you can. Spring has a class that handles Multipart files - org.springframework.web.multipart.MultipartFile. You can use it to send or receive multipart files. But the request body needs to be form-data. You can not send file over x-www-form-urlencoded.

Just use MultipartFile as an attribure in your custom request and you sould be good to go.

@Component
public class CustomRequest {
    ...
    private Long checkSum;
    private MultipartFile file;
    ...
    // make sure you have the getters and setters right
    // also the filed names are spelled exactly the same as they are in the form
    // for example myFile and my_file are different
    
    public MultiValueMap<String, String> getRequestBody() {
        MultiValueMap<String, String> requestBody = new LinkedMultiValueMap<String, String>();
        requestBody.add("checkSum", this.getCheckSum());
        requestBody.add("fileContents", this.getFileContents());
        // add other fileds if you need

        return requestBody;
    }
}

In the controller,

HttpHeaders headers = new HttpHeaders();  
headers.setContentType("mutipart/form-data");    
  
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(customRequest.getRequestBody(), headers);  
  
ResponseEntity<UploadResponse> responseEntity = restTemplate.postForEntity(uploadUrl, requestEntity, UploadResponse.class);

What happened was that you were sending the request body inside the MultiValueMap. You have to send the form data inside the MultiValueMap. And make sure your response has the getters and setters. Spring needs getter setter to serialize the object.

Documentation is here

omar jayed
  • 850
  • 5
  • 16
  • Thank you for the response! When we try to make the rest call through the Spring Rest Template, by constructing a CustomRequest like mentioned above, we get an error stating No Bean Serializer Found. Please note, the request header included the Content Type value as multipart/form-data. Are we missing something? – Sabari Sep 16 '21 at 21:41
  • It’s hard to troubleshoot something without looking at the error. Can you please give the codes for your custom request? – omar jayed Sep 16 '21 at 22:47
  • 1
    I updated my answer based on the code you provided. – omar jayed Sep 17 '21 at 16:29
  • Thank you for the inputs, it helped us move forward! – Sabari Sep 18 '21 at 07:24
  • You're most welcome. – omar jayed Sep 18 '21 at 09:06
0

We made the following changes to finally get it working,

  1. We changed the RestController endpoints attribute annotations, we had the @RequestBody annotation for the attribute UploadRequest, we had to change it to @ModelAttribute as per the suggestions in content-type-multipart-form-databoundary-charset-utf-8-not-supported This helped us overcome the Http Error 415 - UnsupportedMediaType.

  2. On the Client Side, we introduce the class FileSystemResource as per the suggestions in Rest Api Call over Rest Template with MultipartFile

public static class FileSystemResource extends ByteArrayResource {

    private String fileName;

    public FileSystemResource(byte[] byteArray , String filename) {
        super(byteArray);
        this.fileName = filename;
    }

    public String getFilename() { return fileName; }
    public void setFilename(String fileName) { this.fileName= fileName; }

}

then changed the rest call as below,

HttpHeaders headers = new HttpHeaders();  
headers.setContentType("mutipart/form-data");  
  
MultiValueMap<String, Object> map = new MultiValueMap<>();  
map.add("checkSum", request.getCheckSum());
map.add("fileContents", new FileSystemResource(request.getFile().getBytes(), request.getFile().getOriginalFileName()));
  
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(map, headers);  
  
ResponseEntity<UploadResponse> responseEntity = restTemplate.postForEntity(uploadUrl, requestEntity, UploadResponse.class);  

after these changes, it worked.

Sabari
  • 127
  • 1
  • 13