This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 352344c3b969 CAMEL-24112: camel-rest-openapi - Fix path parameters
leaking into query string with multi-param operations
352344c3b969 is described below
commit 352344c3b969dd4398dd467b85d0b84964f8a0b7
Author: Claus Ibsen <[email protected]>
AuthorDate: Thu Jul 16 17:09:21 2026 +0200
CAMEL-24112: camel-rest-openapi - Fix path parameters leaking into query
string with multi-param operations
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: Claus Ibsen <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
---
.../rest/openapi/RestOpenApiEndpoint.java | 13 ++---
.../rest/openapi/RestOpenApiEndpointV3Test.java | 64 ++++++++++++++++++++++
2 files changed, 70 insertions(+), 7 deletions(-)
diff --git
a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpoint.java
b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpoint.java
index 761ca925126c..9c856e06b48e 100644
---
a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpoint.java
+++
b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpoint.java
@@ -683,13 +683,12 @@ public final class RestOpenApiEndpoint extends
DefaultEndpoint {
if (this.parameters != null) {
if (operation.getParameters() != null) {
for (Map.Entry<String, Object> entry :
this.parameters.entrySet()) {
- for (Parameter param : operation.getParameters()) {
- // skip parameters that are part of the operation as
path as otherwise
- // it will be duplicated as query parameter as well
- boolean clash = "path".equals(param.getIn()) &&
entry.getKey().equals(param.getName());
- if (!clash) {
- nestedParameters.put(entry.getKey(),
entry.getValue());
- }
+ // skip parameters that are part of the operation as path
as otherwise
+ // it will be duplicated as query parameter as well
+ boolean clash = operation.getParameters().stream()
+ .anyMatch(p -> "path".equals(p.getIn()) &&
entry.getKey().equals(p.getName()));
+ if (!clash) {
+ nestedParameters.put(entry.getKey(), entry.getValue());
}
}
} else {
diff --git
a/components/camel-rest-openapi/src/test/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpointV3Test.java
b/components/camel-rest-openapi/src/test/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpointV3Test.java
index 24ed458fb49f..f77769d89466 100644
---
a/components/camel-rest-openapi/src/test/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpointV3Test.java
+++
b/components/camel-rest-openapi/src/test/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpointV3Test.java
@@ -287,6 +287,70 @@ public class RestOpenApiEndpointV3Test {
entry("queryParameters", "q={q}&o={o?}"));
}
+ @Test
+ public void shouldNotLeakPathParametersAsQueryParameters() {
+ final CamelContext camelContext = mock(CamelContext.class);
+
+ final RestOpenApiComponent component = new RestOpenApiComponent();
+ component.setCamelContext(camelContext);
+
+ // endpoint parameters include two path params and one extra param
+ Map<String, Object> params = new HashMap<>();
+ params.put("userId", "1");
+ params.put("orderId", "2");
+ params.put("format", "json");
+
+ final RestOpenApiEndpoint endpoint = new RestOpenApiEndpoint(
+ "uri", "remaining", component, params);
+ endpoint.setHost("http://petstore.openapi.io");
+
+ final OpenAPI openapi = new OpenAPI();
+ final Operation operation = new Operation().operationId("getOrder");
+ operation.addParametersItem(new
Parameter().name("userId").in("path").required(true));
+ operation.addParametersItem(new
Parameter().name("orderId").in("path").required(true));
+
+ Map<String, Object> result =
endpoint.determineEndpointParameters(openapi, operation);
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> nested = (Map<String, Object>)
result.get("parameters");
+
+ // path params must not leak into nested parameters
+ assertThat(nested).doesNotContainKey("userId");
+ assertThat(nested).doesNotContainKey("orderId");
+ // non-path param must be preserved
+ assertThat(nested).containsEntry("format", "json");
+ }
+
+ @Test
+ public void shouldKeepEndpointParametersWhenNoPathParamClash() {
+ final CamelContext camelContext = mock(CamelContext.class);
+
+ final RestOpenApiComponent component = new RestOpenApiComponent();
+ component.setCamelContext(camelContext);
+
+ Map<String, Object> params = new HashMap<>();
+ params.put("verbose", "true");
+ params.put("timeout", "5000");
+
+ final RestOpenApiEndpoint endpoint = new RestOpenApiEndpoint(
+ "uri", "remaining", component, params);
+ endpoint.setHost("http://petstore.openapi.io");
+
+ final OpenAPI openapi = new OpenAPI();
+ final Operation operation = new Operation().operationId("listUsers");
+ operation.addParametersItem(new Parameter().name("page").in("query"));
+ operation.addParametersItem(new Parameter().name("limit").in("query"));
+
+ Map<String, Object> result =
endpoint.determineEndpointParameters(openapi, operation);
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> nested = (Map<String, Object>)
result.get("parameters");
+
+ // no path params in the operation, so all endpoint params should be
preserved
+ assertThat(nested).containsEntry("verbose", "true");
+ assertThat(nested).containsEntry("timeout", "5000");
+ }
+
@Test
public void shouldDetermineHostFromRestConfiguration() {
assertThat(RestOpenApiEndpoint.hostFrom(null)).isNull();