Search code examples
springspring-bootspring-mvcresttemplatemultimap

How do i send a post request with Google guava Multi-map data using rest template Spring?


I have a multimap. When I try to send the data over to the backend-server from my frontend-server using restTemplate, it returns a "500 Internal Server Error" error code. It works for normal Map from the java.util.Map class. How do I configure restTemplate so that I send Google guava multimap data over?

This is my frontend-server code in spring boot.

import com.google.common.collect.Multimap;

...

                try
                {
                    RestTemplate rt = new RestTemplate();
                    HttpHeaders headers = new HttpHeaders();
                    headers.setContentType(MediaType.APPLICATION_JSON);
                    List<MediaType> acceptList = new ArrayList<>();
                    acceptList.add(MediaType.APPLICATION_JSON);
                    headers.setAccept(acceptList);

                    Multimap<String, byte[]> arrayMap = ArrayListMultimap.create();
                    arrayMap.put("test", "hello".getBytes());
                    arrayMap.put("title", "meow".getBytes());
                    arrayMap.put("body", "A powerful tool for building web apps.".getBytes());

                    HttpEntity<Multimap<String, byte[]>> uploadEntity = new HttpEntity<>(arrayMap, headers);
                    ResponseEntity<String> response = rt.postForEntity(uri, uploadEntity, String.class);
                    System.out.println(response);
                }
                catch (HttpClientErrorException e)
                {
                    /**
                     *
                     * If we get a HTTP Exception display the error message
                     */
                    logger.error("error http client:  " + e.getResponseBodyAsString());

                }
                catch(Exception e)
                {
                    logger.error("error:  " + e.getMessage());
                }

This is my Backend-server controller where it recevies the incoming data from my frontend-server.

import com.google.common.collect.Multimap;
...
    @PostMapping(path="/rh2lev", consumes = "application/json", produces = "application/json")
    public String setup(@RequestBody Multimap<String, byte[]> uploadIndex)
    {
        System.out.println(uploadIndex);
        return "everything ok";
    }


Solution

  • It seems that this error occurs on serializing Multimap objects into JSON string or deserializing JSON string into Multimap objects. Spring usually does JSON serialization/deserialization by using Jackson ObjectMapper. Jackson ObjectMapper can do JSON serialization/deserialization of java.util.Map objects by default but can't com.google.common.collect.Multimap objects.

    So you need to configure a custom serializer in 'frontend-server' and also configure a custom deserializer in 'backend-server'. I think you can achieve this by using jackson-datatype-guava.

    Example

    Configurations for your 'frontend-server' and 'backend-server'

    (pom.xml)

    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-guava</artifactId>
    </dependency>
    

    (Spring Boot's configuration)

    @Configuration
    public class MyConfigurer  {
    
        @Bean
        public Jackson2ObjectMapperBuilderCustomizer guavaModuleCustomizer() {
            return builder -> {
                builder.modules(new GuavaModule());
            };
        }
    }
    

    Related Question

    Spring MVC mapping Guava Multimap

    For More Information

    “How-to” Guides 4.3. Customize the Jackson ObjectMapper - Spring Boot Reference Documentation
    Intro to the Jackson ObjectMapper - Baeldung blog post
    Jackson – Custom Serializer - Baeldung blog post
    Getting Started with Custom Deserialization in Jackson - Baeldung blog post