androidjsonrestmultipartspring-android

Create Android REST multipart request with one part image and one part json


I have a problem creating Multipart request with Rest template, spring-android and annotations. I have found many examples of using Multipart to upload image or String objects but I can't find any solution on implementing request that is one part image and second part json.

Request should be something like this

Header:

Content-Type: multipart/form-data; boundary=--abcd12345
Authorization:Basic 1234567890

Body:

--abcd12345
Content-Disposition: form-data; name="photo"; filename="image123.jpg"
Content-Type: image/jpeg

<@INCLUDE *C:\Users\John\Desktop\image123.jpg*@>
--abcd12345
Content-Disposition: form-data; name="item"
Content-Type: application/json

{
    "name": "My item",
    "description": "My item description",
    "categories": [1,2]
}
--abcd12345--

I have tried many variations and combinations... I create request with MultiValueMap but all my efforts end in server giving me Cannot consume content type error

If anyone know how to implement this plz do tell. And to clarify problem a little bit more, I cannot use any other libraries like apache mime nor old fashion MultiPartBuilder etc.

This is the most common example on the internet that has one part image and other part String.

    MultiValueMap<String, Object> parts = new LinkedMultiValueMap<String, Object>();
                parts.add("file", new FileSystemResource(fileToUpload));
                parts.add("method", "hello,world");
                String response = mRestClient.uploadFile(parts);

@Rest(rootUrl = "...", converters = {ByteArrayHttpMessageConverter.class, FormHttpMessageConverter.class, StringHttpMessageConverter.class})
public interface RestClient {
    @Post("")
    public String uploadFile(MultiValueMap data);
}

Solution

  • The way I done it:

    // convert image to Base64 String
    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    Bitmap image = getImageFile(imagePath);
    image.compress(Bitmap.CompressFormat.JPEG, 100, stream);
    byte[] imageBytes = stream.toByteArray();
    String encodedImage = Base64.encodeToString(imageBytes, Base64.DEFAULT);
    
    // create new item
    ItemCreateDto newItemDto = new ItemCreateDto();
    newItemDto.setName(new_item_name.getText().toString());
    newItemDto.setDescription(new_item_description.getText().toString());
    ObjectMapper obj = new ObjectMapper();
    String body = obj.writeValueAsString(newItemDto);
    
    MultiValueMap<String, Object> multiValueMap = new LinkedMultiValueMap<String, Object>();
    
    // create header with content-disposition for image part
    HttpHeaders imageHeaders = new HttpHeaders();
    imageHeaders.add("Content-Disposition", "form-data; name=photo; filename=photo.jpeg");
    imageHeaders.setContentType(MediaType.IMAGE_JPEG);
    HttpEntity<String> imageEntity = new HttpEntity<String>(encodedImage, imageHeaders);
    
    // create header for data part
    HttpHeaders dataHeaders = new HttpHeaders();
    dataHeaders.add("Content-Disposition", "form-data; name=item");
    dataHeaders.setContentType(MediaType.APPLICATION_JSON);
    HttpEntity<String> dataEntity = new HttpEntity<String>(body, dataHeaders);
    
    // add headers to multiValueMap
    multiValueMap.add("photo", imageEntity);
    multiValueMap.add("item", dataEntity);
    
    newItemAPI.createItem(multiValueMap);
    

    And AndroidAnnotation + Android Spring part:

    @Rest(rootUrl = "", converters = { ByteArrayHttpMessageConverter.class,    MappingJackson2HttpMessageConverter.class, FormHttpMessageConverter.class })
    public interface INewItemRestClient {
    
    @Post("")
    @Accept(MediaType.APPLICATION_JSON)
    @RequiresHeader({"Authorization", "Content-Type"})
    String createItem(MultiValueMap<String, Object> data);
    

    hope this will help you...