From 73984c6a1ad1f40293f865369cebc78dea9dbd94 Mon Sep 17 00:00:00 2001 From: Hyunwoo Gu Date: Mon, 1 Dec 2025 23:37:13 +0900 Subject: [PATCH 1/3] Handle empty and slash-prefixed URIs in apply() method - Updated RootUriTemplateHandler.apply() to: - Prefix rootUri if uriTemplate starts with '/' - Return rootUri if uriTemplate is blank - This ensures correct behavior for empty and relative paths Signed-off-by: Hyunwoo Gu --- .../boot/restclient/RootUriTemplateHandler.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/module/spring-boot-restclient/src/main/java/org/springframework/boot/restclient/RootUriTemplateHandler.java b/module/spring-boot-restclient/src/main/java/org/springframework/boot/restclient/RootUriTemplateHandler.java index 85f4471bff50..5839405e4b17 100644 --- a/module/spring-boot-restclient/src/main/java/org/springframework/boot/restclient/RootUriTemplateHandler.java +++ b/module/spring-boot-restclient/src/main/java/org/springframework/boot/restclient/RootUriTemplateHandler.java @@ -30,6 +30,7 @@ * * @author Phillip Webb * @author Scott Frederick + * @author Hyunwoo Gu * @since 4.0.0 */ public class RootUriTemplateHandler implements UriTemplateHandler { @@ -64,7 +65,9 @@ public URI expand(String uriTemplate, @Nullable Object... uriVariables) { String apply(String uriTemplate) { String rootUri = getRootUri(); if (rootUri != null && StringUtils.startsWithIgnoreCase(uriTemplate, "/")) { - return getRootUri() + uriTemplate; + return rootUri + uriTemplate; + } else if (rootUri != null && uriTemplate.isBlank()) { + return rootUri; } return uriTemplate; } From 734e4b8cdcb9c4ac72ed94a38236338f4d46bfcf Mon Sep 17 00:00:00 2001 From: Hyunwoo Gu Date: Mon, 1 Dec 2025 23:38:02 +0900 Subject: [PATCH 2/3] Add unit tests for apply() method handling empty and slash-prefixed URIs - Added tests for RootUriTemplateHandler.apply() covering: - URIs starting with '/' - Empty string - Blank string - Absolute URLs - Relative paths - Ensures apply() behaves as expected in all edge cases Signed-off-by: Hyunwoo Gu --- .../boot/restclient/RootUriBuilderFactoryTests.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/module/spring-boot-restclient/src/test/java/org/springframework/boot/restclient/RootUriBuilderFactoryTests.java b/module/spring-boot-restclient/src/test/java/org/springframework/boot/restclient/RootUriBuilderFactoryTests.java index 7251decdd0b2..445d93d93c0e 100644 --- a/module/spring-boot-restclient/src/test/java/org/springframework/boot/restclient/RootUriBuilderFactoryTests.java +++ b/module/spring-boot-restclient/src/test/java/org/springframework/boot/restclient/RootUriBuilderFactoryTests.java @@ -32,6 +32,7 @@ * Tests for {@link RootUriBuilderFactory}. * * @author Scott Frederick + * @author Hyunwoo Gu */ class RootUriBuilderFactoryTests { @@ -43,4 +44,12 @@ void uriStringPrefixesRoot() throws URISyntaxException { assertThat(builder.build()).isEqualTo(new URI("https://example.com/hello")); } + @Test + void uriStringWhenEmptyShouldReturnRoot() throws URISyntaxException { + UriBuilderFactory builderFactory = new RootUriBuilderFactory("https://example.com", + mock(UriTemplateHandler.class)); + UriBuilder builder = builderFactory.uriString(""); + assertThat(builder.build()).isEqualTo(new URI("https://example.com")); + } + } From 8c70a7fd0c45ff7961da25993279b43e62a01f12 Mon Sep 17 00:00:00 2001 From: Hyunwoo Gu Date: Tue, 2 Dec 2025 01:01:57 +0900 Subject: [PATCH 3/3] Refactor RootUriBuilderFactoryTests to initialize common setup in BeforeEach Annotation Signed-off-by: Hyunwoo Gu --- .../RootUriBuilderFactoryTests.java | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/module/spring-boot-restclient/src/test/java/org/springframework/boot/restclient/RootUriBuilderFactoryTests.java b/module/spring-boot-restclient/src/test/java/org/springframework/boot/restclient/RootUriBuilderFactoryTests.java index 445d93d93c0e..1a0e2311d4e9 100644 --- a/module/spring-boot-restclient/src/test/java/org/springframework/boot/restclient/RootUriBuilderFactoryTests.java +++ b/module/spring-boot-restclient/src/test/java/org/springframework/boot/restclient/RootUriBuilderFactoryTests.java @@ -19,6 +19,7 @@ import java.net.URI; import java.net.URISyntaxException; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.web.util.UriBuilder; @@ -36,20 +37,28 @@ */ class RootUriBuilderFactoryTests { + private String rootUri; + + private UriBuilderFactory builderFactory; + + @BeforeEach + void setUp() { + this.rootUri = "https://example.com"; + this.builderFactory = new RootUriBuilderFactory(this.rootUri, mock(UriTemplateHandler.class)); + } + @Test void uriStringPrefixesRoot() throws URISyntaxException { - UriBuilderFactory builderFactory = new RootUriBuilderFactory("https://example.com", - mock(UriTemplateHandler.class)); - UriBuilder builder = builderFactory.uriString("/hello"); + UriBuilder builder = this.builderFactory.uriString("/hello"); assertThat(builder.build()).isEqualTo(new URI("https://example.com/hello")); } @Test void uriStringWhenEmptyShouldReturnRoot() throws URISyntaxException { - UriBuilderFactory builderFactory = new RootUriBuilderFactory("https://example.com", - mock(UriTemplateHandler.class)); - UriBuilder builder = builderFactory.uriString(""); - assertThat(builder.build()).isEqualTo(new URI("https://example.com")); + UriBuilder builder = this.builderFactory.uriString(""); + + URI builtUri = builder.build(); + assertThat(builtUri).isEqualTo(new URI(this.rootUri)); } }