Skip to content

Commit 297e307

Browse files
committed
Fix handling of UriTemplateRequestEntity in TestRestTemplate
A change [1] in Spring Framework 5.3 means that getUrl() on a RequestEntity will throw an UnsupportedOperationException if the entity was created using a template. This commit updates TestRestTemplate to check for instances of UriTemplateRequestEntity and to resolve the URI using the entity's UriTemplateHandler instead of calling getUrl() directly. Fixes gh-25097 [1] spring-projects/spring-framework@a0f4d81
1 parent 788a42d commit 297e307

File tree

2 files changed

+51
-3
lines changed

2 files changed

+51
-3
lines changed

spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/client/TestRestTemplate.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2020 the original author or authors.
2+
* Copyright 2012-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -41,6 +41,7 @@
4141
import org.springframework.http.HttpHeaders;
4242
import org.springframework.http.HttpMethod;
4343
import org.springframework.http.RequestEntity;
44+
import org.springframework.http.RequestEntity.UriTemplateRequestEntity;
4445
import org.springframework.http.ResponseEntity;
4546
import org.springframework.http.client.ClientHttpRequestFactory;
4647
import org.springframework.http.client.ClientHttpResponse;
@@ -965,7 +966,7 @@ public TestRestTemplate withBasicAuth(String username, String password) {
965966
@SuppressWarnings({ "rawtypes", "unchecked" })
966967
private RequestEntity<?> createRequestEntityWithRootAppliedUri(RequestEntity<?> requestEntity) {
967968
return new RequestEntity(requestEntity.getBody(), requestEntity.getHeaders(), requestEntity.getMethod(),
968-
applyRootUriIfNecessary(requestEntity.getUrl()), requestEntity.getType());
969+
applyRootUriIfNecessary(resolveUri(requestEntity)), requestEntity.getType());
969970
}
970971

971972
private URI applyRootUriIfNecessary(URI uri) {
@@ -976,6 +977,23 @@ private URI applyRootUriIfNecessary(URI uri) {
976977
return uri;
977978
}
978979

980+
private URI resolveUri(RequestEntity<?> entity) {
981+
if (entity instanceof UriTemplateRequestEntity) {
982+
UriTemplateRequestEntity<?> templatedUriEntity = (UriTemplateRequestEntity<?>) entity;
983+
if (templatedUriEntity.getVars() != null) {
984+
return this.restTemplate.getUriTemplateHandler().expand(templatedUriEntity.getUriTemplate(),
985+
templatedUriEntity.getVars());
986+
}
987+
else if (templatedUriEntity.getVarsMap() != null) {
988+
return this.restTemplate.getUriTemplateHandler().expand(templatedUriEntity.getUriTemplate(),
989+
templatedUriEntity.getVarsMap());
990+
}
991+
throw new IllegalStateException(
992+
"No variables specified for URI template: " + templatedUriEntity.getUriTemplate());
993+
}
994+
return entity.getUrl();
995+
}
996+
979997
/**
980998
* Options used to customize the Apache HTTP Client.
981999
*/

spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/client/TestRestTemplateTests.java

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -233,6 +233,36 @@ void withBasicAuthShouldUseNoOpErrorHandler() throws Exception {
233233
Class.forName("org.springframework.boot.test.web.client.TestRestTemplate$NoOpResponseErrorHandler"));
234234
}
235235

236+
@Test
237+
void exchangeWithRelativeTemplatedUrlRequestEntity() throws Exception {
238+
RequestEntity<Void> entity = RequestEntity.get("/a/b/c.{ext}", "txt").build();
239+
TestRestTemplate template = new TestRestTemplate();
240+
ClientHttpRequestFactory requestFactory = mock(ClientHttpRequestFactory.class);
241+
MockClientHttpRequest request = new MockClientHttpRequest();
242+
request.setResponse(new MockClientHttpResponse(new byte[0], HttpStatus.OK));
243+
URI absoluteUri = URI.create("http://localhost:8080/a/b/c.txt");
244+
given(requestFactory.createRequest(eq(absoluteUri), eq(HttpMethod.GET))).willReturn(request);
245+
template.getRestTemplate().setRequestFactory(requestFactory);
246+
LocalHostUriTemplateHandler uriTemplateHandler = new LocalHostUriTemplateHandler(new MockEnvironment());
247+
template.setUriTemplateHandler(uriTemplateHandler);
248+
template.exchange(entity, String.class);
249+
verify(requestFactory).createRequest(eq(absoluteUri), eq(HttpMethod.GET));
250+
}
251+
252+
@Test
253+
void exchangeWithAbsoluteTemplatedUrlRequestEntity() throws Exception {
254+
RequestEntity<Void> entity = RequestEntity.get("https://api.example.com/a/b/c.{ext}", "txt").build();
255+
TestRestTemplate template = new TestRestTemplate();
256+
ClientHttpRequestFactory requestFactory = mock(ClientHttpRequestFactory.class);
257+
MockClientHttpRequest request = new MockClientHttpRequest();
258+
request.setResponse(new MockClientHttpResponse(new byte[0], HttpStatus.OK));
259+
URI absoluteUri = URI.create("https://api.example.com/a/b/c.txt");
260+
given(requestFactory.createRequest(eq(absoluteUri), eq(HttpMethod.GET))).willReturn(request);
261+
template.getRestTemplate().setRequestFactory(requestFactory);
262+
template.exchange(entity, String.class);
263+
verify(requestFactory).createRequest(eq(absoluteUri), eq(HttpMethod.GET));
264+
}
265+
236266
@Test
237267
void deleteHandlesRelativeUris() throws IOException {
238268
verifyRelativeUriHandling(TestRestTemplate::delete);

0 commit comments

Comments
 (0)