Resttemplate form/multipart: image + JSON in POST

13,727

If you want to use ByteArrayResource, simply register a ResourceHttpMessageConverter.

If you want to use a byte[], simply register a ByteArrayHttpMessageConverter.

The content type of the image part should be an image type, like image/png, not application/json.

You can set each individual part's data type with

HttpHeaders partHeaders = new HttpHeaders();
partHeaders.setContentType(MediaType.IMAGE_PNG);
HttpEntity<ByteArrayResource> bytesPart = new HttpEntity<ByteArrayResource>(bytes, partHeaders);

map.add("file", bytesPart);

Create your RestTemplate by providing your collection of HttpMessageConverters

HttpMessageConverter<Object> jackson = new MappingJackson2HttpMessageConverter();
HttpMessageConverter<Resource> resource = new ResourceHttpMessageConverter();
FormHttpMessageConverter formHttpMessageConverter = new FormHttpMessageConverter();
formHttpMessageConverter.addPartConverter(jackson);
formHttpMessageConverter.addPartConverter(resource); // This is hope driven programming

RestTemplate restTemplate = new RestTemplate(Arrays.asList(jackson, resource, formHttpMessageConverter));

and your outermost HttpEntity should have a multipart content type

header.setContentType(MediaType.MULTIPART_FORM_DATA);
Share:
13,727

Related videos on Youtube

TamasGyorfi
Author by

TamasGyorfi

Updated on September 15, 2022

Comments

  • TamasGyorfi
    TamasGyorfi over 1 year

    I'm trying to call a rest ws (using resttemplate), that accepts an image and some JSON. However, I don't seem to be able to get it running.

    The relevant code is as follows:

        HttpHeaders header = new HttpHeaders();
        header.setContentType(MediaType.MULTIPART_FORM_DATA);
    
        MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
        ByteArrayResource bytes = new ByteArrayResource(pictureData) {
            @Override
            public String getFilename() {
                return pictureName;
            }
        };
        map.add("x", x);
        map.add("file", bytes);
    
        HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity(map, header);
        String response =  restTemplate.postForObject(UPLOAD_URL, requestEntity, String.class);
    

    Where x is some POJO with all the required JSON annotations (I receive it from another web service, that part works ok).

    This thing, however, tells me: HttpMessageNotWritableException: Could not write request: no suitable HttpMessageConverter found for x.

    If I change ByteArrayResource to byte[] then I get a 400 Bad Request. If I change the content type to JSON, then ByteArrayResource cannot be serialized into JSON:

    Caused by: org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: No serializer found for class java.io.ByteArrayInputStream and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: org.springframework.util.LinkedMultiValueMap["file"]->java.util.LinkedList[0]->a.b.c.["inputStream"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class java.io.ByteArrayInputStream and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: org.springframework.util.LinkedMultiValueMap["file"]->java.util.LinkedList[0]->a.b.c.["inputStream"])
    

    I have the following converters configured:

    StringHttpMessageConverter,
    MappingJackson2HttpMessageConverter
    FormHttpMessageConverter
    

    Any ideas, please? Thanks in advance.

    UPDATE

    So this is what I currently have after the instructions: I register the converters like this:

        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
        restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
    
        FormHttpMessageConverter formHttpMessageConverter = new FormHttpMessageConverter();
            formHttpMessageConverter.addPartConverter(new MappingJackson2HttpMessageConverter());
            formHttpMessageConverter.addPartConverter(new ResourceHttpMessageConverter()); // This is hope driven programming
    
        restTemplate.getMessageConverters().add(new ResourceHttpMessageConverter());
        restTemplate.getMessageConverters().add(formHttpMessageConverter);
    

    Then in the ws call I have:

        HttpHeaders header = new HttpHeaders();
        header.setContentType(MediaType.APPLICATION_JSON); //Also tried with multipart...
    
        MultiValueMap<String, Object> multipartRequest = new LinkedMultiValueMap<>();
    
        ByteArrayResource bytes = new ByteArrayResource(pictureData) {
            @Override
            public String getFilename() {
                return pictureName;
            }
        };
    
        HttpHeaders xHeader = new HttpHeaders();
        xHeader.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<X> xPart = new HttpEntity<>(x, xHeader);
        multipartRequest.add("x", xPart);
    
        HttpHeaders pictureHeader = new HttpHeaders();
        pictureHeader.setContentType(MediaType.IMAGE_PNG);
        HttpEntity<ByteArrayResource> picturePart = new HttpEntity<>(bytes, pictureHeader);
        multipartRequest.add("file", picturePart);
    
        HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity(multipartRequest, header);
        return restTemplate.postForObject(UPLOAD_URL, requestEntity, String.class);