2

I've a Spring Boot 2.2.5 application calling this REST endpoint

@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)

My caller does

val url = clientUri.toString() + configuration.getUrl().getUseableProvidersForNetworks(); % 'providers/usable/search?'
val builder = UriComponentsBuilder.fromHttpUrl(url)
      .queryParam("usages[]", USAGES)
      .queryParam("network-ids[]", networkIds);
val response =
      restTemplate.exchange(
          builder.toUriString(),
          HttpMethod.GET,
          entity,
          new ParameterizedTypeReference<List<Provider>>() {});

where USAGES is a Set<Usage> and networkIds is a List<Integer>.

The RestTemplate is created by

RestTemplate eurekaRestTemplate() {
    val requestFactory = new HttpComponentsClientHttpRequestFactory();
    requestFactory.setReadTimeout(TIMEOUT);
    requestFactory.setConnectTimeout(TIMEOUT);
    return new RestTemplate(new BufferingClientHttpRequestFactory(requestFactory));
  }

Problem: The [] get double encoded to %255B%255D and I end up with a call to

providers/usable/search?usages%255B%255D=MESSAGE_DELIVERY&network-ids%255B%255D=2145118475&network-ids%255B%255D=-1536358371

Which obviously doesn't work; the server misses e.g. usages[]. It works with curl with [] instead of %255B%255D.

How can I avoid that?

I'm aware of this issue and the docs, but that didn't help yet.

3 Answers 3

3

The solution was to call UriComponentsBuilder.build(false) to instruct the UriComponentsBuilder not to encode the url:

val response = restTemplate.exchange(
              builder.build(false).toUriString(),
              HttpMethod.GET,
              entity,
              new ParameterizedTypeReference<List<Provider>>() {});

This is tricky because a test with Mockito/JUnit of this will tell you that the url is not encoded while a test with MockRestServiceServer will show one level of encoding ([] become %5B%5D).

Sign up to request clarification or add additional context in comments.

Comments

3

If you wish to pass the encoded url directly to RestTemplate, you can instruct RestTemplate to not encode the url by passing the java.net.URI instead of a String. Here's an example using org.springframework.web.util.UriComponents

String url = "https://someurl/this%2Fis%2Fencoded/";
UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(url).build(true);
ResponseEntity<String[]> file = template.exchange(uriComponents.toUri(), 
HttpMethod.GET, entity,String[].class);

By passing UriComponentsBuilder.fromHttpUrl(url).build(true) You are essentially letting UriComponents know that your url is already encoded.

Comments

1

I think you shouldn't be dealing with using []. I mean, it's not necessary to name your parameters using "[]". Why would you do that?

val builder = UriComponentsBuilder.fromHttpUrl(url)
      .queryParam("usages", USAGES)
      .queryParam("network-ids", networkIds);

will perfectly work for:

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)

Hope it helps!

Hint: be careful when using array/collection parameters on URLs, there's a URL length limit that you must consider

1 Comment

Thanks, but the API is as it is. I would use @RequestBody .

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.