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();