This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch fix/CAMEL-24112 in repository https://gitbox.apache.org/repos/asf/camel.git
commit 93964b58553fe1d668e8c888635bd3293e2c794b Author: Claus Ibsen <[email protected]> AuthorDate: Thu Jul 16 15:55:16 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]> --- .../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();
