This is an automated email from the ASF dual-hosted git repository.

Aias00 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git


The following commit(s) were added to refs/heads/master by this push:
     new f4a22f9a29 fix(sdk): compose path variable and request param url 
rewrites (#7420)
f4a22f9a29 is described below

commit f4a22f9a29c0bc57757bd388a288d47f50a0f0d0
Author: Sean-Walker0 <[email protected]>
AuthorDate: Sun Oct 4 19:16:51 2026 +0800

    fix(sdk): compose path variable and request param url rewrites (#7420)
    
    PathVariableParameterProcessor and RequestParamParameterProcessor each
    rebuilt the URL from the original RequestTemplate (getUrl() +
    getPath()), so whatever an earlier processor had written to
    ShenyuRequest.url was discarded:
    
    - @PathVariable first, @RequestParam second: the request param
      processor rebuilt from the raw template path and reintroduced the
      unresolved {id} placeholder (/orders/{id}?expand=all)
    - @RequestParam first, @PathVariable second: the path variable
      processor overwrote the query string (/orders/one, query lost)
    
    Both processors now mutate the live URL in place. RequestTemplate#request()
    initializes ShenyuRequest.url to url + path, so substituting placeholders
    and appending query parameters on the current value makes the two
    rewrites compose in any declaration order.
    
    The existing processor test fixtures initialized the request with an
    empty URL, diverging from the runtime initialization; they are aligned
    with RequestTemplate#request() (assertions unchanged).
    
    Fixes #6489
    
    Co-authored-by: Sean-Walker0 
<[email protected]>
---
 .../annotation/PathVariableParameterProcessor.java | 12 +--
 .../annotation/RequestParamParameterProcessor.java | 12 +--
 .../ParameterProcessorUrlCompositionTest.java      | 89 ++++++++++++++++++++++
 .../PathVariableParameterProcessorTest.java        |  6 +-
 .../RequestParamParameterProcessorTest.java        |  6 +-
 5 files changed, 107 insertions(+), 18 deletions(-)

diff --git 
a/shenyu-sdk/shenyu-sdk-spring/src/main/java/org/apache/shenyu/sdk/spring/annotation/PathVariableParameterProcessor.java
 
b/shenyu-sdk/shenyu-sdk-spring/src/main/java/org/apache/shenyu/sdk/spring/annotation/PathVariableParameterProcessor.java
index 75771b4114..3b7e5480b7 100644
--- 
a/shenyu-sdk/shenyu-sdk-spring/src/main/java/org/apache/shenyu/sdk/spring/annotation/PathVariableParameterProcessor.java
+++ 
b/shenyu-sdk/shenyu-sdk-spring/src/main/java/org/apache/shenyu/sdk/spring/annotation/PathVariableParameterProcessor.java
@@ -50,24 +50,24 @@ public class PathVariableParameterProcessor implements 
AnnotatedParameterProcess
         if (arg instanceof String) {
             String varName = "{" + name + "}";
             String varNameRegex = "\\{" + name + "\\}";
-            if (requestTemplate.getPath().contains(varName)) {
-                shenyuRequest.setUrl(requestTemplate.getUrl() + 
RegExUtils.replaceAll(requestTemplate.getPath(), varNameRegex, 
String.valueOf(arg)));
+            if (shenyuRequest.getUrl().contains(varName)) {
+                
shenyuRequest.setUrl(RegExUtils.replaceAll(shenyuRequest.getUrl(), 
varNameRegex, String.valueOf(arg)));
             }
             return true;
         }
-        String path = requestTemplate.getPath();
+        String url = shenyuRequest.getUrl();
         for (Map.Entry<?, ?> entry : ((Map<?, ?>) arg).entrySet()) {
             final Object key = entry.getKey();
             final Object value = entry.getValue();
             if (key instanceof String && value instanceof String) {
                 String varName = "{" + key + "}";
                 String varNameRegex = "\\{" + key + "\\}";
-                if (path.contains(varName)) {
-                    path = RegExUtils.replaceAll(path, varNameRegex, (String) 
value);
+                if (url.contains(varName)) {
+                    url = RegExUtils.replaceAll(url, varNameRegex, (String) 
value);
                 }
             }
         }
-        shenyuRequest.setUrl(requestTemplate.getUrl() + path);
+        shenyuRequest.setUrl(url);
         return true;
     }
 }
diff --git 
a/shenyu-sdk/shenyu-sdk-spring/src/main/java/org/apache/shenyu/sdk/spring/annotation/RequestParamParameterProcessor.java
 
b/shenyu-sdk/shenyu-sdk-spring/src/main/java/org/apache/shenyu/sdk/spring/annotation/RequestParamParameterProcessor.java
index cad6cbaf55..981218836b 100644
--- 
a/shenyu-sdk/shenyu-sdk-spring/src/main/java/org/apache/shenyu/sdk/spring/annotation/RequestParamParameterProcessor.java
+++ 
b/shenyu-sdk/shenyu-sdk-spring/src/main/java/org/apache/shenyu/sdk/spring/annotation/RequestParamParameterProcessor.java
@@ -48,7 +48,7 @@ public class RequestParamParameterProcessor implements 
AnnotatedParameterProcess
         String name = requestParam.value();
         checkState(StringUtils.isNotBlank(name) || arg instanceof Map, 
"RequestParam.value() was empty on parameter %s#%s",
             requestTemplate.getMethod().getDeclaringClass().getSimpleName(), 
requestTemplate.getMethod().getName());
-        StringBuilder pathResult = new 
StringBuilder(requestTemplate.getPath());
+        StringBuilder urlResult = new StringBuilder(shenyuRequest.getUrl());
         Map<Object, Object> params = Maps.newHashMap();
         if (!(arg instanceof Map) && !(arg instanceof MultipartFile)) {
             params.put(name, arg);
@@ -56,14 +56,14 @@ public class RequestParamParameterProcessor implements 
AnnotatedParameterProcess
             params = (Map<Object, Object>) arg;
         }
         params.forEach((key, value) -> {
-            if (pathResult.indexOf("?") > 0) {
-                pathResult.append("&");
+            if (urlResult.indexOf("?") > 0) {
+                urlResult.append("&");
             } else {
-                pathResult.append("?");
+                urlResult.append("?");
             }
-            pathResult.append(key).append("=").append(value);
+            urlResult.append(key).append("=").append(value);
         });
-        shenyuRequest.setUrl(requestTemplate.getUrl() + pathResult);
+        shenyuRequest.setUrl(urlResult.toString());
         return true;
     }
 
diff --git 
a/shenyu-sdk/shenyu-sdk-spring/src/test/java/org/apache/shenyu/sdk/spring/annotation/ParameterProcessorUrlCompositionTest.java
 
b/shenyu-sdk/shenyu-sdk-spring/src/test/java/org/apache/shenyu/sdk/spring/annotation/ParameterProcessorUrlCompositionTest.java
new file mode 100644
index 0000000000..4fbddff612
--- /dev/null
+++ 
b/shenyu-sdk/shenyu-sdk-spring/src/test/java/org/apache/shenyu/sdk/spring/annotation/ParameterProcessorUrlCompositionTest.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shenyu.sdk.spring.annotation;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import org.apache.shenyu.sdk.core.ShenyuRequest;
+import org.apache.shenyu.sdk.core.common.RequestTemplate;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestParam;
+
+/**
+ * {@link PathVariable} and {@link RequestParam} url composition test.
+ */
+public final class ParameterProcessorUrlCompositionTest {
+
+    private static final String BASE_URL = "http://localhost:9195";;
+
+    private PathVariableParameterProcessor pathVariableProcessor;
+
+    private RequestParamParameterProcessor requestParamProcessor;
+
+    private Method clientMethod;
+
+    @BeforeEach
+    public void init() throws NoSuchMethodException {
+        this.pathVariableProcessor = new PathVariableParameterProcessor();
+        this.requestParamProcessor = new RequestParamParameterProcessor();
+        this.clientMethod = TestClient.class.getMethod("get", String.class, 
String.class);
+    }
+
+    @Test
+    public void pathVariableThenRequestParamCompose() {
+        final ShenyuRequest request = newRequest("/orders/{id}");
+
+        this.pathVariableProcessor.processArgument(request, 
annotation(PathVariable.class), "one");
+        this.requestParamProcessor.processArgument(request, 
annotation(RequestParam.class), "all");
+
+        assertEquals(BASE_URL + "/orders/one?expand=all", request.getUrl());
+    }
+
+    @Test
+    public void requestParamThenPathVariableCompose() {
+        final ShenyuRequest request = newRequest("/orders/{id}");
+
+        this.requestParamProcessor.processArgument(request, 
annotation(RequestParam.class), "all");
+        this.pathVariableProcessor.processArgument(request, 
annotation(PathVariable.class), "one");
+
+        assertEquals(BASE_URL + "/orders/one?expand=all", request.getUrl());
+    }
+
+    private <T extends java.lang.annotation.Annotation> T annotation(final 
Class<T> annotationType) {
+        return 
this.clientMethod.getParameters()[0].isAnnotationPresent(annotationType)
+                ? 
this.clientMethod.getParameters()[0].getAnnotation(annotationType)
+                : 
this.clientMethod.getParameters()[1].getAnnotation(annotationType);
+    }
+
+    private ShenyuRequest newRequest(final String path) {
+        final RequestTemplate template = new RequestTemplate(Void.class, 
this.clientMethod, "get",
+                BASE_URL, "", path, ShenyuRequest.HttpMethod.GET, null, null, 
null);
+        return ShenyuRequest.create(ShenyuRequest.HttpMethod.GET,
+                template.getUrl() + template.getPath(), new HashMap<>(), "", 
"test", template);
+    }
+
+    interface TestClient {
+
+        @GetMapping("/orders/{id}")
+        Object get(@PathVariable("id") String id, @RequestParam("expand") 
String expand);
+    }
+}
diff --git 
a/shenyu-sdk/shenyu-sdk-spring/src/test/java/org/apache/shenyu/sdk/spring/annotation/PathVariableParameterProcessorTest.java
 
b/shenyu-sdk/shenyu-sdk-spring/src/test/java/org/apache/shenyu/sdk/spring/annotation/PathVariableParameterProcessorTest.java
index ef1701aade..7f71dd19ed 100644
--- 
a/shenyu-sdk/shenyu-sdk-spring/src/test/java/org/apache/shenyu/sdk/spring/annotation/PathVariableParameterProcessorTest.java
+++ 
b/shenyu-sdk/shenyu-sdk-spring/src/test/java/org/apache/shenyu/sdk/spring/annotation/PathVariableParameterProcessorTest.java
@@ -51,7 +51,7 @@ public class PathVariableParameterProcessorTest {
     @ParameterizedTest
     
@MethodSource("org.apache.shenyu.sdk.spring.annotation.PathVariableParameterProcessorTest#templateStream")
     public void processArgumentNullTest(final RequestTemplate template) {
-        this.request = ShenyuRequest.create(ShenyuRequest.HttpMethod.POST, "", 
Maps.newHashMap(), "", "test", template);
+        this.request = ShenyuRequest.create(ShenyuRequest.HttpMethod.POST, 
template.getUrl() + template.getPath(), Maps.newHashMap(), "", "test", 
template);
         final PathVariable path = spy(PathVariable.class);
         when(path.value()).thenReturn("");
 
@@ -65,7 +65,7 @@ public class PathVariableParameterProcessorTest {
     @ParameterizedTest
     
@MethodSource("org.apache.shenyu.sdk.spring.annotation.PathVariableParameterProcessorTest#templateStream")
     public void processArgumentStringTest(final RequestTemplate template) {
-        this.request = ShenyuRequest.create(ShenyuRequest.HttpMethod.POST, "", 
Maps.newHashMap(), "", "test", template);
+        this.request = ShenyuRequest.create(ShenyuRequest.HttpMethod.POST, 
template.getUrl() + template.getPath(), Maps.newHashMap(), "", "test", 
template);
         final PathVariable path = spy(PathVariable.class);
         when(path.value()).thenReturn("id");
 
@@ -77,7 +77,7 @@ public class PathVariableParameterProcessorTest {
     @ParameterizedTest
     
@MethodSource("org.apache.shenyu.sdk.spring.annotation.PathVariableParameterProcessorTest#templateStream")
     public void processArgumentMapTest(final RequestTemplate template) {
-        this.request = ShenyuRequest.create(ShenyuRequest.HttpMethod.POST, "", 
Maps.newHashMap(), "", "test", template);
+        this.request = ShenyuRequest.create(ShenyuRequest.HttpMethod.POST, 
template.getUrl() + template.getPath(), Maps.newHashMap(), "", "test", 
template);
         Map<String, String> pathParam = Maps.newHashMap();
         pathParam.put("id", "idValue");
         pathParam.put("name", "nameValue");
diff --git 
a/shenyu-sdk/shenyu-sdk-spring/src/test/java/org/apache/shenyu/sdk/spring/annotation/RequestParamParameterProcessorTest.java
 
b/shenyu-sdk/shenyu-sdk-spring/src/test/java/org/apache/shenyu/sdk/spring/annotation/RequestParamParameterProcessorTest.java
index c5449d61ec..827f687ac4 100644
--- 
a/shenyu-sdk/shenyu-sdk-spring/src/test/java/org/apache/shenyu/sdk/spring/annotation/RequestParamParameterProcessorTest.java
+++ 
b/shenyu-sdk/shenyu-sdk-spring/src/test/java/org/apache/shenyu/sdk/spring/annotation/RequestParamParameterProcessorTest.java
@@ -56,7 +56,7 @@ public class RequestParamParameterProcessorTest {
     @Test
     public void processArgumentNullTest() {
         RequestTemplate template = new RequestTemplate(Void.class, method1, 
"method1", "/dev/url/param", "", "/path", ShenyuRequest.HttpMethod.GET, null, 
null, null);
-        this.request = ShenyuRequest.create(ShenyuRequest.HttpMethod.POST, "", 
Maps.newHashMap(), "", "test", template);
+        this.request = ShenyuRequest.create(ShenyuRequest.HttpMethod.POST, 
template.getUrl() + template.getPath(), Maps.newHashMap(), "", "test", 
template);
         final RequestParam param = spy(RequestParam.class);
         when(param.value()).thenReturn("");
 
@@ -66,7 +66,7 @@ public class RequestParamParameterProcessorTest {
     @Test
     public void processArgumentStringTest() {
         RequestTemplate template = new RequestTemplate(Void.class, method1, 
"method1", "/dev/url/param", "", "/path", ShenyuRequest.HttpMethod.GET, null, 
null, null);
-        this.request = ShenyuRequest.create(ShenyuRequest.HttpMethod.POST, "", 
Maps.newHashMap(), "", "test", template);
+        this.request = ShenyuRequest.create(ShenyuRequest.HttpMethod.POST, 
template.getUrl() + template.getPath(), Maps.newHashMap(), "", "test", 
template);
         final RequestParam param = spy(RequestParam.class);
         when(param.value()).thenReturn("id");
 
@@ -78,7 +78,7 @@ public class RequestParamParameterProcessorTest {
     @Test
     public void processArgumentMapTest() {
         RequestTemplate template = new RequestTemplate(Void.class, method2, 
"method1", "/dev/url/param", "", "/path", ShenyuRequest.HttpMethod.GET, null, 
null, null);
-        this.request = ShenyuRequest.create(ShenyuRequest.HttpMethod.POST, "", 
Maps.newHashMap(), "", "test", template);
+        this.request = ShenyuRequest.create(ShenyuRequest.HttpMethod.POST, 
template.getUrl() + template.getPath(), Maps.newHashMap(), "", "test", 
template);
         final RequestParam param = spy(RequestParam.class);
 
         Map<String, Object> params = Maps.newHashMap();

Reply via email to