Reputation: 4591
I have a Spring Boot 2 service with a method
@RequestMapping(path = "/usable/search")
public List<Provider> findUsable(
@RequestParam(name = "country-id", required = false) Integer countryId,
@RequestParam(name = "network-ids[]", required = false) List<Integer> networkIds,
@RequestParam(name = "usages[]") Set<Usage> usages)
I want to call that service from another Spring Boot service. For this I do
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
val response =
restTemplate.exchange(
"http://castor-v2/providers/usable/search?network-ids[]={0}&usages[]={1}",
HttpMethod.GET,
new HttpEntity<Long>(httpHeaders),
new ParameterizedTypeReference<List<Provider>>() {},
Collections.singletonList(networkId),
Collections.singleton(Usage.MESSAGE_DELIVERY));
This generates a http request like search?network-ids[]=[428]&usages[]=[MESSAGE_DELIVERY]
which is wrong (the server bombs with org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.util.List'; nested exception is java.lang.NumberFormatException: For input string: "[573]"
); correct would be search?network-ids[]=77371&usages[]=MESSAGE_DELIVERY
.
Most likely the URI template is wrong. How should it be to use with Java collections?
Update: I created a new api endpoint without the brackets and used UriComponentsBuilder
as suggested by @vatsal.
Upvotes: 0
Views: 1786
Reputation: 187
To easily manipulate URLs / path / params / etc., you can use Spring's UriComponentsBuilder class. It's cleaner that manually concatenating strings and it takes care of the URL encoding for you:
Simple code to do this using RestTemplate will be as follows:
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
String url = "http://castor-v2/providers/usable/search";
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("country-id", countryId)
.queryParam("network-ids[]", networkId)
.queryParam("usages[]", Usage.MESSAGE_DELIVERY);
HttpEntity<?> entity = new HttpEntity<>(httpHeaders);
HttpEntity<String> response = restTemplate.exchange(
builder.toUriString(),
HttpMethod.GET,
entity,
String.class);
This should resolve your query. Also, make sure you pass Usage as a String. If you still want to continue using Usage as an Object then instead of RequestParam you can use RequestBody and pass it as Body to the POST call.
Upvotes: 2
Reputation: 109
It probably converts the singletonList to a string. Which will include the block brackets. So you can either convert the list to a string beforehand or create your own list implementation which has a to string method that converts the values to a comma separated list.
Upvotes: 1
Reputation: 565
You cannot pass a object as request param. Request parameters are a Multi values map of String to String. if you want to pass Usage as String You can create method like this
@RequestMapping(path = "/usable/search")
public List<Provider> findUsable(
@RequestParam(name = "country-id", required = false) Integer countryId,
@RequestParam(name = "networkIds", required = false) List<Integer> networkIds,
@RequestParam(name = "usages") Set<String> usages)
To call this service
http://castor-v2/providers/usable/search?networkIds=0&networkIds=1&usages=usages1&usages=usages2
Upvotes: 1