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 d5c92b0656dd CAMEL-24113: camel-rest-openapi - Fix rest-openapi 
producer cross-contamination for same operation
d5c92b0656dd is described below

commit d5c92b0656dd3d1d10f807f3f87662ea35d2dd88
Author: Claus Ibsen <[email protected]>
AuthorDate: Thu Jul 16 17:09:54 2026 +0200

    CAMEL-24113: camel-rest-openapi - Fix rest-openapi producer 
cross-contamination for same operation
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    CAMEL-24113: camel-rest-openapi - Include produces, consumes, 
queryParameters, and producerComponentName in delegate rest: endpoint URI to 
prevent cross-contamination between routes targeting the same operation
    
    Signed-off-by: Claus Ibsen <[email protected]>
    Co-authored-by: Claude Opus 4.6 <[email protected]>
---
 .../rest/openapi/RestOpenApiEndpoint.java          |  34 +++++-
 .../rest/openapi/RestOpenApiEndpointV3Test.java    | 121 +++++++++++++++++++++
 2 files changed, 154 insertions(+), 1 deletion(-)

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 9c856e06b48e..67cf9b92e73c 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
@@ -559,8 +559,40 @@ public final class RestOpenApiEndpoint extends 
DefaultEndpoint {
         boolean hasHost = params.containsKey("host");
         String basePath = determineBasePath(openapi);
         String componentEndpointUri = "rest:" + method + ":" + basePath + ":" 
+ uriTemplate;
+
+        // include all distinguishing options in the URI so each unique 
combination
+        // gets its own cached endpoint and avoids cross-contamination 
(CAMEL-24113)
+        StringBuilder query = new StringBuilder();
         if (hasHost) {
-            componentEndpointUri += "?host=" + params.get("host");
+            query.append("host=").append(params.get("host"));
+        }
+        if (params.containsKey("producerComponentName")) {
+            if (!query.isEmpty()) {
+                query.append('&');
+            }
+            
query.append("producerComponentName=").append(params.get("producerComponentName"));
+        }
+        if (params.containsKey("consumes")) {
+            if (!query.isEmpty()) {
+                query.append('&');
+            }
+            query.append("consumes=").append(params.get("consumes"));
+        }
+        if (params.containsKey("produces")) {
+            if (!query.isEmpty()) {
+                query.append('&');
+            }
+            query.append("produces=").append(params.get("produces"));
+        }
+        if (params.containsKey("queryParameters")) {
+            if (!query.isEmpty()) {
+                query.append('&');
+            }
+            query.append("queryParameters=")
+                    
.append(UnsafeUriCharactersEncoder.encode(params.get("queryParameters").toString()));
+        }
+        if (!query.isEmpty()) {
+            componentEndpointUri += "?" + query;
         }
 
         Endpoint endpoint = camelContext.getEndpoint(componentEndpointUri);
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 f77769d89466..3a6d00bc2ed4 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
@@ -568,6 +568,127 @@ public class RestOpenApiEndpointV3Test {
         
assertThat(endpoint.literalPathParameterValue(pathParameter)).isEqualTo("va%20lue");
     }
 
+    @Test
+    public void shouldNotCrossContaminateProducersForSameOperation() throws 
Exception {
+        final CamelContext camelContext = new DefaultCamelContext();
+        camelContext.start();
+
+        try {
+            final RestOpenApiComponent component = new 
RestOpenApiComponent(camelContext);
+            camelContext.addComponent("rest-openapi", component);
+
+            final OpenAPI openapi = new OpenAPI();
+            openapi.addServersItem(new 
Server().url("http://petstore.example.com";));
+            final Operation operation = new 
Operation().operationId("findPets");
+
+            // first endpoint: produces JSON
+            final RestOpenApiEndpoint endpoint1 = new RestOpenApiEndpoint(
+                    "rest-openapi:spec#findPets", "spec#findPets", component, 
Collections.emptyMap());
+            endpoint1.setCamelContext(camelContext);
+            endpoint1.setHost("http://petstore.example.com";);
+            endpoint1.setProduces("application/json");
+
+            // second endpoint: produces XML
+            final RestOpenApiEndpoint endpoint2 = new RestOpenApiEndpoint(
+                    "rest-openapi:spec#findPets", "spec#findPets", component, 
Collections.emptyMap());
+            endpoint2.setCamelContext(camelContext);
+            endpoint2.setHost("http://petstore.example.com";);
+            endpoint2.setProduces("application/xml");
+
+            endpoint1.createProducerFor(openapi, operation, "get", "/pets");
+            endpoint2.createProducerFor(openapi, operation, "get", "/pets");
+
+            // the two delegate rest: endpoints must be distinct instances
+            long restEndpointCount = camelContext.getEndpoints().stream()
+                    .filter(e -> e.getEndpointUri().startsWith("rest:"))
+                    .count();
+            assertThat(restEndpointCount)
+                    .as("Two rest-openapi endpoints with different 'produces' 
should create two distinct rest: delegate endpoints")
+                    .isEqualTo(2);
+
+            // verify each has the correct produces value
+            org.apache.camel.component.rest.RestEndpoint restEp1 = 
camelContext.getEndpoints().stream()
+                    .filter(e -> e.getEndpointUri().startsWith("rest:"))
+                    .filter(e -> 
e.getEndpointUri().contains("produces=application/json"))
+                    
.map(org.apache.camel.component.rest.RestEndpoint.class::cast)
+                    .findFirst().orElseThrow();
+            assertThat(restEp1.getProduces()).isEqualTo("application/json");
+
+            org.apache.camel.component.rest.RestEndpoint restEp2 = 
camelContext.getEndpoints().stream()
+                    .filter(e -> e.getEndpointUri().startsWith("rest:"))
+                    .filter(e -> 
e.getEndpointUri().contains("produces=application/xml"))
+                    
.map(org.apache.camel.component.rest.RestEndpoint.class::cast)
+                    .findFirst().orElseThrow();
+            assertThat(restEp2.getProduces()).isEqualTo("application/xml");
+        } finally {
+            camelContext.stop();
+        }
+    }
+
+    @Test
+    public void shouldNotCrossContaminateQueryParameters() throws Exception {
+        final CamelContext camelContext = new DefaultCamelContext();
+        camelContext.start();
+
+        try {
+            final RestOpenApiComponent component = new 
RestOpenApiComponent(camelContext);
+            camelContext.addComponent("rest-openapi", component);
+
+            final OpenAPI openapi = new OpenAPI();
+            openapi.addServersItem(new 
Server().url("http://petstore.example.com";));
+            final Operation operation = new 
Operation().operationId("findPetsByStatus");
+
+            // first endpoint: status=available
+            Map<String, Object> params1 = new HashMap<>();
+            params1.put("status", "available");
+            final RestOpenApiEndpoint endpoint1 = new RestOpenApiEndpoint(
+                    "rest-openapi:spec#findPetsByStatus", 
"spec#findPetsByStatus", component, params1);
+            endpoint1.setCamelContext(camelContext);
+            endpoint1.setHost("http://petstore.example.com";);
+
+            // second endpoint: status=sold
+            Map<String, Object> params2 = new HashMap<>();
+            params2.put("status", "sold");
+            final RestOpenApiEndpoint endpoint2 = new RestOpenApiEndpoint(
+                    "rest-openapi:spec#findPetsByStatus", 
"spec#findPetsByStatus", component, params2);
+            endpoint2.setCamelContext(camelContext);
+            endpoint2.setHost("http://petstore.example.com";);
+
+            // add a query parameter to the operation
+            operation.addParametersItem(new 
Parameter().name("status").in("query").required(true));
+
+            endpoint1.createProducerFor(openapi, operation, "get", 
"/pet/findByStatus");
+            endpoint2.createProducerFor(openapi, operation, "get", 
"/pet/findByStatus");
+
+            // verify two distinct delegate endpoints
+            long restEndpointCount = camelContext.getEndpoints().stream()
+                    .filter(e -> e.getEndpointUri().startsWith("rest:"))
+                    .count();
+            assertThat(restEndpointCount)
+                    .as("Two rest-openapi endpoints with different 
queryParameters should create two distinct rest: delegate endpoints")
+                    .isEqualTo(2);
+
+            // verify each has the correct query parameter value
+            org.apache.camel.component.rest.RestEndpoint restEp1 = 
camelContext.getEndpoints().stream()
+                    .filter(e -> e.getEndpointUri().startsWith("rest:"))
+                    .filter(e -> e instanceof 
org.apache.camel.component.rest.RestEndpoint)
+                    
.map(org.apache.camel.component.rest.RestEndpoint.class::cast)
+                    .filter(e -> e.getQueryParameters() != null && 
e.getQueryParameters().contains("status=available"))
+                    .findFirst().orElseThrow();
+            
assertThat(restEp1.getQueryParameters()).contains("status=available");
+
+            org.apache.camel.component.rest.RestEndpoint restEp2 = 
camelContext.getEndpoints().stream()
+                    .filter(e -> e.getEndpointUri().startsWith("rest:"))
+                    .filter(e -> e instanceof 
org.apache.camel.component.rest.RestEndpoint)
+                    
.map(org.apache.camel.component.rest.RestEndpoint.class::cast)
+                    .filter(e -> e.getQueryParameters() != null && 
e.getQueryParameters().contains("status=sold"))
+                    .findFirst().orElseThrow();
+            assertThat(restEp2.getQueryParameters()).contains("status=sold");
+        } finally {
+            camelContext.stop();
+        }
+    }
+
     @Test
     public void shouldUseDefaultSpecificationUri() {
         final RestOpenApiComponent component = new RestOpenApiComponent();

Reply via email to