Sabari
Sabari

Reputation: 157

MultipartFile inside Custom Request / Response Objects

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

Upvotes: 0

Views: 3409

Answers (2)

Sabari
Sabari

Reputation: 157

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.

Upvotes: 0

omar jayed
omar jayed

Reputation: 868

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

Upvotes: 1

Related Questions