Using a map to set parameters for a rest call using RestTemplate

Emilien Brigand picture Emilien Brigand · Jul 10, 2015 · Viewed 15.5k times · Source

I am currently using a piece of code to set parameters and I do a REST call to a URL using restTemplate, it works fine:

MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
map.add("grant_type", grantType);
map.add("client_id", clientId);
map.add("client_secret", clientSecret);
HttpEntity<?> entity = new HttpEntity<Object>(map);
restTemplate.exchange("myurl", HttpMethod.POST, entity, Void.class);

But if I am using a LinkedMultiValueMap it's because I looked on the web ;)

And if I replace it by a HashMap, it works as well, so can anyone tell me the advantage of using a LinkedMultiValueMap ?

Code with HashMap:

Map<String, String> map = new HashMap<String, String>();
map.put("grant_type", grantType);
map.put("client_id", clientId);
map.put("client_secret", clientSecret);
HttpEntity<?> entity = new HttpEntity<Object>(map);
restTemplate.exchange("myurl", HttpMethod.POST, entity, Void.class);

I can see we can preserve the order of the parameters in the LinkedMultiValueMap, but it does not matter in my project... And so if orders matters I still could use a LinkedHashMap

EDIT:

It looks like I need the MultiValueMap if I use APPLICATION_FORM_URLENCODED and HashMap, this code throw an exception :

Map<String, String> map = new HashMap<String, String>();
map.add("grant_type", grantType);
map.add("client_id", clientId);
map.add("client_secret", clientSecret);
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<?> entity = new HttpEntity<Object>(map, headers);
restTemplate.exchange("myurl", HttpMethod.POST, entity, Void.class);

Exception:

org.springframework.web.client.RestClientException: Could not write request: no suitable HttpMessageConverter found for request type [java.util.HashMap] and content type [application/x-www-form-urlencoded]
        at org.springframework.web.client.RestTemplate$HttpEntityRequestCallback.doWithRequest(RestTemplate.java:784)
        at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:567)
        at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:530)
        at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:448)
        at uk.co.wowcher.marketplace.commons.rest.RestTemplateUtils.getForEntity(RestTemplateUtils.java:54)
        at uk.co.wowcher.marketplace.submission.service.ParameterService.getProductParameterVOs(ParameterService.java:38)
        at uk.co.wowcher.marketplace.submission.service.ParameterService$$FastClassBySpringCGLIB$$3f87231d.invoke(<generated>)
        at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
        at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:717)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
        at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:85)
        at uk.co.wowcher.marketplace.submission.logging.MarketplaceLogger.logMethodCalls(MarketplaceLogger.java:27)
        at sun.reflect.GeneratedMethodAccessor72.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:483)
        at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:621)
        at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:610)
        at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:68)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653)
        at uk.co.xxx.marketplace.submission.service.ParameterService$$EnhancerBySpringCGLIB$$a52b80b.getProductParameterVOs(<generated>)
        at uk.co.xxx.marketplace.submission.service.SubmissionService.getAgreementData(SubmissionService.java:449)
       at uk.co.xxx.marketplace.submission.service.SubmissionService$$FastClassBySpringCGLIB$$92bbe798.invoke(<generated>)
        at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
        at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:717)

So, it looks like that setting some parameters with a HashMap is not a good idea at all... So I removed the accepted answer for now, waiting more explanation on this point... And I have the suitable converter (converters.add(new FormHttpMessageConverter());), I mean if I use a MultiValueMap I don't have the exception, so the HashMap is the problem!

Answer

aryn.galadar picture aryn.galadar · Jul 10, 2015

The only real advantage of using a LinkedMultiValueMap over other Map implementations is that it can store multiple values.

This is useful if you need to pass multiple values for the same key (for instance, if you need to pass a set of form checkbox values).

See the JavaDoc here.

In your case, since you only have one value per key, you should be able to safely use a HashMap.