spring resttemplate url encoding
Depends on which version of Spring you're using. If your version is too old, for example, version 3.0.6.RELEASE, you'll not have such facility as UriComponentsBuilder
with your spring-web jar.
What you need is to prevent Spring RestTemplate from encoding the URL. What you could do is:
import java.net.URI;
StringBuilder builder = new StringBuilder("http://");
builder.append(endpointUrl);
builder.append("?method=logout&session=");
builder.append(sessionId);
URI uri = URI.create(builder.toString());
restTemplate.getForObject(uri, Object.class);
I tested it with Spring version 3.0.6.RELEASE, and it works.
In a word, instead of using restTemplate.getForObject(String url, Object.class)
, use restTemplate.getForObject(java.net.URI uri, Object.class)
See the rest-resttemplate-uri section of the Spring document
You can use the overloaded variant that takes a java.net.URI instead public T getForObject(URI url, Class responseType) throws RestClientException
From Spring's own documentation
UriComponents uriComponents =
UriComponentsBuilder.fromUriString("http://example.com/hotels/{hotel}/bookings/{booking}").build()
.expand("42", "21")
.encode();
URI uri = uriComponents.toUri();
Looks like I found best native way (up-to-date) solution:
- Do not pass encoded url string as parameter to
RestTemplate.exchange()
- Use URI object instead. Use
UriComponentsBuilder
to construct URI.
See (simplified) example below:
String instanceUrl = "https://abc.my.salesforce.com"
HttpEntity<String> entity = new HttpEntity<>(headers);
UriComponents uriComponents =
UriComponentsBuilder.fromHttpUrl(instanceUrl)
.path("/services/data/v45.0/query/")
.queryParam("q", String.format(sqlSelect, id))
.build();
ResponseEntity<OpportunityLineItem> responseEntity =
restTemplate.exchange(
uriComponents.toUri(), HttpMethod.GET,
entity, OpportunityLineItem.class);
// Wrong! URI string will be double encoded
/*
ResponseEntity<OpportunityLineItem> responseEntity =
restTemplate.exchange(
uriComponents.toUriString(), HttpMethod.GET,
entity, OpportunityLineItem.class);
*/
This way you will not get issue with double encoding.
Solution was found while debugging SalesForce REST client, based on Spring RestTemplate
client (including SOQL queries).
There is no easy way to do this. URI template variables are usually meant for path elements or a query string parameters. You're trying to pass a host. Ideally, you'd find a better solution for constructing the URI. I suggest Yuci's solution.
If you still want to work with Spring utilities and template expansion, one workaround is to use UriTemplate
to produce the URL with the URI variables as you have them, then URL-decode it and pass that to your RestTemplate
.
String url = "http://{enpointUrl}?method=logout&session={sessionId}";
URI expanded = new UriTemplate(url).expand(endpointUrl, sessionId); // this is what RestTemplate uses
url = URLDecoder.decode(expanded.toString(), "UTF-8"); // java.net class
template.getForObject(url, Object.class);