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-spring-boot.git


The following commit(s) were added to refs/heads/main by this push:
     new 0419afd39bf CAMEL-24351: camel-platform-http-starter - the request 
mapping must not be lazy (#1874)
0419afd39bf is described below

commit 0419afd39bf1eb03aa5c9353b5ae63765729209c
Author: henrik242 <[email protected]>
AuthorDate: Tue Aug 4 16:15:55 2026 +0200

    CAMEL-24351: camel-platform-http-starter - the request mapping must not be 
lazy (#1874)
    
    @Lazy was added in 4.21.0, replacing an ObjectProvider that deferred the
    CamelContext lookup. CamelRequestHandlerMapping registers itself as a
    PlatformHttpListener and is only notified of endpoints created after it
    exists, so creating it on first demand is unordered with respect to
    CamelContext startup. When Camel starts first the mapping learns about no
    endpoint at all, and every platform-http route answers 404 while reporting
    itself as started. 4.18.3 and 4.20.0 both instantiated the bean eagerly.
---
 .../SpringBootPlatformHttpAutoConfiguration.java   | 15 +++-
 .../SpringBootPlatformHttpEagerMappingTest.java    | 85 ++++++++++++++++++++++
 2 files changed, 97 insertions(+), 3 deletions(-)

diff --git 
a/components-starter/camel-platform-http-starter/src/main/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpAutoConfiguration.java
 
b/components-starter/camel-platform-http-starter/src/main/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpAutoConfiguration.java
index ce1cdbd0682..f317e79169b 100644
--- 
a/components-starter/camel-platform-http-starter/src/main/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpAutoConfiguration.java
+++ 
b/components-starter/camel-platform-http-starter/src/main/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpAutoConfiguration.java
@@ -22,13 +22,13 @@ import 
org.apache.camel.component.platform.http.spi.PlatformHttpEngine;
 import org.apache.camel.spring.boot.ComponentConfigurationProperties;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.ObjectProvider;
 import org.springframework.boot.autoconfigure.AutoConfiguration;
 import 
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
 import 
org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.boot.thread.Threading;
 import org.springframework.boot.web.server.autoconfigure.ServerProperties;
 import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Lazy;
 import org.springframework.core.env.Environment;
 import org.springframework.core.task.SimpleAsyncTaskExecutor;
 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@@ -90,9 +90,18 @@ public class SpringBootPlatformHttpAutoConfiguration {
         return new SpringBootPlatformHttpEngine(port, executor);
     }
 
+    /**
+     * The mapping registers itself as a {@link 
org.apache.camel.component.platform.http.PlatformHttpListener} and is
+     * only notified of endpoints created after it exists, so it must be 
eager. A lazy mapping is created on first
+     * demand, which is unordered with respect to CamelContext startup: if 
Camel starts first, every platform-http
+     * endpoint is already registered and the mapping never learns about any 
of them, leaving all of them unreachable
+     * with a 404 while the routes report themselves as started. CamelContext 
is taken as an ObjectProvider and
+     * resolved inside the method to avoid the circular dependency that 
injecting it directly would create.
+     */
     @Bean
-    @Lazy
-    public CamelRequestHandlerMapping 
platformHttpEngineRequestMapping(PlatformHttpEngine engine, CamelContext 
camelContext) {
+    public CamelRequestHandlerMapping platformHttpEngineRequestMapping(
+            PlatformHttpEngine engine, ObjectProvider<CamelContext> 
camelContextProvider) {
+        CamelContext camelContext = camelContextProvider.getObject();
         PlatformHttpComponent component = 
camelContext.getComponent("platform-http", PlatformHttpComponent.class);
         return new CamelRequestHandlerMapping(component, engine);
     }
diff --git 
a/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpEagerMappingTest.java
 
b/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpEagerMappingTest.java
new file mode 100644
index 00000000000..26ecdc0fd38
--- /dev/null
+++ 
b/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpEagerMappingTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.camel.component.platform.http.springboot;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.test.spring.junit6.CamelSpringBootTest;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * {@link CamelRequestHandlerMapping} registers itself as a platform-http 
listener and is only notified of endpoints
+ * created after it exists. It must therefore be instantiated eagerly: 
creating it on first demand is unordered with
+ * respect to CamelContext startup, and when Camel starts first the mapping 
never learns about the endpoints that
+ * already exist, so every platform-http route is answered with 404 while 
reporting itself as started.
+ * <p>
+ * That the context starts at all also covers the circular dependency the 
ObjectProvider avoids.
+ */
+@EnableAutoConfiguration
+@CamelSpringBootTest
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, 
classes = { CamelAutoConfiguration.class,
+        SpringBootPlatformHttpEagerMappingTest.class,
+        SpringBootPlatformHttpEagerMappingTest.TestConfiguration.class,
+        PlatformHttpComponentAutoConfiguration.class, 
SpringBootPlatformHttpAutoConfiguration.class })
+public class SpringBootPlatformHttpEagerMappingTest {
+
+    @Autowired
+    ConfigurableApplicationContext applicationContext;
+
+    @Autowired
+    CamelRequestHandlerMapping mapping;
+
+    @Test
+    void mappingMustNotBeLazy() {
+        Assertions.assertThat(applicationContext.getBeanFactory()
+                
.getBeanDefinition("platformHttpEngineRequestMapping").isLazyInit())
+                .isFalse();
+    }
+
+    @Test
+    void endpointIsMapped() {
+        assertThat(mapping.getHandlerMethods().keySet().stream()
+                .map(RequestMappingInfo::getPathPatternsCondition)
+                .anyMatch(condition -> condition != null && 
condition.getPatternValues().contains("/eager")))
+                .isTrue();
+    }
+
+    @Configuration
+    public static class TestConfiguration {
+
+        @Bean
+        public RouteBuilder routeBuilder() {
+            return new RouteBuilder() {
+                @Override
+                public void configure() {
+                    from("platform-http:/eager").routeId("eager-route")
+                            .setBody().constant("alive");
+                }
+            };
+        }
+    }
+}

Reply via email to