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

gnodet 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 a7dffe7a779e CAMEL-24825: fix REST OpenAPI missing/pathless servers 
entry (#26801)
a7dffe7a779e is described below

commit a7dffe7a779e0a56f794f2f99724b98531ff5f56
Author: Guillaume Nodet <[email protected]>
AuthorDate: Thu Sep 24 11:06:27 2026 +0200

    CAMEL-24825: fix REST OpenAPI missing/pathless servers entry (#26801)
    
    Root cause: both RestOpenApiHelper.determineBasePath() and
    RestOpenApiEndpoint.determineBasePath() used isNotEmpty() to check the
    return value of getBasePathFromOpenApi(). When a servers entry exists
    but the URL has no path (e.g. http://localhost:8080), getBasePathFromOpenApi
    returns "" which isNotEmpty() treats as absent, causing a spurious fall-
    through to DEFAULT_BASE_PATH ("/"). This produced a mismatched registered
    request path and 404 responses for every operation in the contract.
    
    When there is no servers entry at all, the old code also fell through to
    DEFAULT_BASE_PATH but then the resulting URI (rest:METHOD:/:template)
    caused a JDK-level "URI is not absolute" exception at consumer creation.
    
    Fix: in both determineBasePath methods, only fall back to DEFAULT_BASE_PATH
    when openapi.getServers() is null or empty. When servers are present, use a
    != null guard (instead of isNotEmpty) so that an empty string base path from
    a pathless server URL is correctly honoured.
    
    Co-authored-by: Claude Sonnet 4.6 <[email protected]>
---
 .../rest/openapi/RestOpenApiEndpoint.java          | 11 ++--
 .../component/rest/openapi/RestOpenApiHelper.java  |  7 ++-
 .../rest/openapi/RestOpenApiEndpointV3Test.java    | 61 ++++++++++++++++++++++
 3 files changed, 74 insertions(+), 5 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 0abb19e54be0..1b108d15b081 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
@@ -627,9 +627,14 @@ public final class RestOpenApiEndpoint extends 
DefaultEndpoint {
             return restConfigurationBasePath;
         }
 
-        final String specificationBasePath = 
RestOpenApiHelper.getBasePathFromOpenApi(openapi);
-        if (isNotEmpty(specificationBasePath)) {
-            return specificationBasePath;
+        // Only fall back to DEFAULT_BASE_PATH when there are no servers 
entries at all.
+        // When servers are present but the URL has no path, 
getBasePathFromOpenApi returns ""
+        // which isNotEmpty() would wrongly treat as absent — so we use != 
null here.
+        if (openapi != null && openapi.getServers() != null && 
!openapi.getServers().isEmpty()) {
+            final String specificationBasePath = 
RestOpenApiHelper.getBasePathFromOpenApi(openapi);
+            if (specificationBasePath != null) {
+                return specificationBasePath;
+            }
         }
 
         return RestOpenApiComponent.DEFAULT_BASE_PATH;
diff --git 
a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiHelper.java
 
b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiHelper.java
index 4e2fcd559aa2..0b692d1a36b7 100644
--- 
a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiHelper.java
+++ 
b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiHelper.java
@@ -124,9 +124,12 @@ public final class RestOpenApiHelper {
         }
 
         // openapi spec should be last, as all the above can override the 
configuration
-        if (openAPI != null) {
+        // Only fall back to DEFAULT_BASE_PATH when there are no servers 
entries at all.
+        // When servers are present but the URL has no path, 
getBasePathFromOpenApi returns ""
+        // which isNotEmpty() would wrongly treat as absent — so we use != 
null here.
+        if (openAPI != null && openAPI.getServers() != null && 
!openAPI.getServers().isEmpty()) {
             String specificationBasePath = 
RestOpenApiHelper.getBasePathFromOpenApi(openAPI);
-            if (isNotEmpty(specificationBasePath)) {
+            if (specificationBasePath != null) {
                 return specificationBasePath;
             }
         }
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 3a6d00bc2ed4..baf634ad0d08 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
@@ -213,6 +213,67 @@ public class RestOpenApiEndpointV3Test {
                 .isEqualTo("/endpoint");
     }
 
+    @Test
+    void shouldDetermineEmptyBasePathFromOpenApiServer() {
+        final RestConfiguration restConfiguration = new RestConfiguration();
+
+        final CamelContext camelContext = mock(CamelContext.class);
+        
when(camelContext.getRestConfiguration()).thenReturn(restConfiguration);
+
+        // Pathless server URL: http://localhost:8080 (no path component)
+        final OpenAPI openapi = new OpenAPI();
+        openapi.addServersItem(new Server().url("http://localhost:8080";));
+
+        final RestOpenApiComponent component = new RestOpenApiComponent();
+        component.setCamelContext(camelContext);
+
+        final RestOpenApiEndpoint endpoint = new RestOpenApiEndpoint(
+                "rest-openapi:getPetById", "getPetById", component,
+                Collections.emptyMap());
+
+        assertThat(RestOpenApiHelper.getBasePathFromOpenApi(openapi))
+                .as("OpenAPI server without a path should produce an empty 
base path")
+                .isEmpty();
+
+        assertThat(endpoint.determineBasePath(openapi))
+                .as("When the OpenAPI server URL has no path, the base path 
should be empty (not default '/')")
+                .isEmpty();
+
+        assertThat(RestOpenApiHelper.determineBasePath(camelContext, 
component, endpoint, openapi))
+                .as("RestOpenApiHelper.determineBasePath should also return 
empty for a pathless server URL")
+                .isEmpty();
+    }
+
+    @Test
+    void shouldDefaultBasePathWhenNoServersInSpec() {
+        final RestConfiguration restConfiguration = new RestConfiguration();
+
+        final CamelContext camelContext = mock(CamelContext.class);
+        
when(camelContext.getRestConfiguration()).thenReturn(restConfiguration);
+
+        // OpenAPI spec with no servers entry at all
+        final OpenAPI openapi = new OpenAPI();
+
+        final RestOpenApiComponent component = new RestOpenApiComponent();
+        component.setCamelContext(camelContext);
+
+        final RestOpenApiEndpoint endpoint = new RestOpenApiEndpoint(
+                "rest-openapi:getPetById", "getPetById", component,
+                Collections.emptyMap());
+
+        assertThat(RestOpenApiHelper.getBasePathFromOpenApi(openapi))
+                .as("OpenAPI with no servers should return null from 
getBasePathFromOpenApi")
+                .isNull();
+
+        assertThat(endpoint.determineBasePath(openapi))
+                .as("When the OpenAPI spec has no servers entry, the base path 
should fall back to default '/'")
+                .isEqualTo("/");
+
+        assertThat(RestOpenApiHelper.determineBasePath(camelContext, 
component, endpoint, openapi))
+                .as("RestOpenApiHelper.determineBasePath should fall back to 
'/' when spec has no servers")
+                .isEqualTo("/");
+    }
+
     @Test
     public void shouldDetermineEndpointParameters() {
         final CamelContext camelContext = mock(CamelContext.class);

Reply via email to