Skip to content

Commit f737205

Browse files
committed
Support dynamic default uri variables for RestClient
Closes GH-34189
1 parent b6de2b0 commit f737205

File tree

3 files changed

+70
-3
lines changed

3 files changed

+70
-3
lines changed

spring-web/src/main/java/org/springframework/web/util/UriComponents.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2025 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.
@@ -24,6 +24,8 @@
2424
import java.util.Iterator;
2525
import java.util.List;
2626
import java.util.Map;
27+
import java.util.function.Function;
28+
import java.util.function.Supplier;
2729
import java.util.function.UnaryOperator;
2830
import java.util.regex.Matcher;
2931
import java.util.regex.Pattern;
@@ -42,6 +44,7 @@
4244
* @author Arjen Poutsma
4345
* @author Juergen Hoeller
4446
* @author Rossen Stoyanchev
47+
* @author Yanming Zhou
4548
* @since 3.1
4649
* @see UriComponentsBuilder
4750
*/
@@ -233,6 +236,7 @@ public final String toString() {
233236
return expandUriComponent(source, uriVariables, null);
234237
}
235238

239+
@SuppressWarnings({"unchecked", "rawtypes"})
236240
static @Nullable String expandUriComponent(@Nullable String source, UriTemplateVariables uriVariables,
237241
@Nullable UnaryOperator<String> encoder) {
238242

@@ -254,6 +258,12 @@ public final String toString() {
254258
if (UriTemplateVariables.SKIP_VALUE.equals(varValue)) {
255259
continue;
256260
}
261+
if (varValue instanceof Supplier supplier) {
262+
varValue = supplier.get();
263+
}
264+
else if (varValue instanceof Function function) {
265+
varValue = function.apply(varName);
266+
}
257267
String formatted = getVariableValueAsString(varValue);
258268
formatted = encoder != null ? encoder.apply(formatted) : Matcher.quoteReplacement(formatted);
259269
matcher.appendReplacement(sb, formatted);

spring-web/src/test/java/org/springframework/web/client/RestClientBuilderTests.java

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 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.
@@ -20,8 +20,10 @@
2020
import java.net.URI;
2121
import java.util.ArrayList;
2222
import java.util.Collections;
23+
import java.util.HashMap;
2324
import java.util.List;
2425
import java.util.Map;
26+
import java.util.function.Function;
2527

2628
import org.assertj.core.api.InstanceOfAssertFactories;
2729
import org.jspecify.annotations.Nullable;
@@ -44,6 +46,7 @@
4446
* @author Arjen Poutsma
4547
* @author Sebastien Deleuze
4648
* @author Nicklas Wiegandt
49+
* @author Yanming Zhou
4750
*/
4851
public class RestClientBuilderTests {
4952

@@ -110,6 +113,23 @@ void defaultUri() {
110113
assertThat(fieldValue("baseUrl", defaultBuilder)).isEqualTo(baseUrl.toString());
111114
}
112115

116+
@Test
117+
void baseUriWithDynamicDefaultUriVariables() {
118+
String key = "partition";
119+
String baseUrl = "http://{" + key + "}.example.com";
120+
Map<String, String> holder = new HashMap<>();
121+
RestClient restClient = RestClient.builder().baseUrl(baseUrl)
122+
.defaultUriVariables(Map.of(key, (Function<String, String>) holder::get)).build();
123+
124+
holder.put(key, "p0");
125+
assertThat(fieldValue("uri", restClient.get().uri("/{foo}.html", Map.of("foo", "index")))
126+
.toString()).isEqualTo("http://p0.example.com/index.html");
127+
128+
holder.put(key, "p1");
129+
assertThat(fieldValue("uri", restClient.get().uri("/{bar}.html", Map.of("bar", "index")))
130+
.toString()).isEqualTo("http://p1.example.com/index.html");
131+
}
132+
113133
@Test
114134
void messageConvertersList() {
115135
StringHttpMessageConverter stringConverter = new StringHttpMessageConverter();
@@ -281,4 +301,17 @@ void buildCopiesDefaultCookiesImmutable() {
281301
return null;
282302
}
283303
}
304+
305+
private static @Nullable Object fieldValue(String name, Object instance) {
306+
try {
307+
Field field = instance.getClass().getDeclaredField(name);
308+
field.setAccessible(true);
309+
310+
return field.get(instance);
311+
}
312+
catch (NoSuchFieldException | IllegalAccessException ex) {
313+
fail(ex.getMessage(), ex);
314+
return null;
315+
}
316+
}
284317
}

spring-web/src/test/java/org/springframework/web/util/UriComponentsTests.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 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.
@@ -23,6 +23,9 @@
2323
import java.net.URI;
2424
import java.util.Arrays;
2525
import java.util.Collections;
26+
import java.util.Map;
27+
import java.util.function.Function;
28+
import java.util.function.Supplier;
2629

2730
import org.junit.jupiter.api.Test;
2831
import org.junit.jupiter.params.ParameterizedTest;
@@ -42,6 +45,7 @@
4245
* @author Arjen Poutsma
4346
* @author Phillip Webb
4447
* @author Rossen Stoyanchev
48+
* @author Yanming Zhou
4549
*/
4650
class UriComponentsTests {
4751

@@ -266,4 +270,24 @@ void equalsOpaqueUriComponents(ParserType parserType) {
266270
assertThat(uric1).isNotEqualTo(uric3);
267271
}
268272

273+
@Test
274+
void expandSupplier() {
275+
String key = "partition";
276+
Map<String, String> holder = Map.of(key, "p0");
277+
UriComponents uri = UriComponentsBuilder.fromUriString("http://{" + key + "}.example.com")
278+
.uriVariables(Map.of(key, (Supplier<String>) () -> holder.get(key))).build();
279+
280+
assertThat(uri.toString()).isEqualTo("http://p0.example.com");
281+
}
282+
283+
@Test
284+
void expandFunction() {
285+
String key = "partition";
286+
Map<String, String> holder = Map.of(key, "p0");
287+
UriComponents uri = UriComponentsBuilder.fromUriString("http://{" + key + "}.example.com")
288+
.uriVariables(Map.of(key, (Function<String, String>) holder::get)).build();
289+
290+
assertThat(uri.toString()).isEqualTo("http://p0.example.com");
291+
}
292+
269293
}

0 commit comments

Comments
 (0)