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 a842fd64d892 CAMEL-23550: Fix bean lookup in route templates to check 
local repository (#23312)
a842fd64d892 is described below

commit a842fd64d8925ad9b26f716dc96d9d9f458ee080
Author: Tom Cunningham <[email protected]>
AuthorDate: Tue May 19 14:56:15 2026 -0400

    CAMEL-23550: Fix bean lookup in route templates to check local repository 
(#23312)
    
    * CAMEL-23550: Fix bean lookup in route templates to check local repository 
first
    
    Kamelets defining beans via the beans: section store them in a local bean 
repository
    scoped to the RouteTemplateContext. The reifier now checks this local 
repository before
    falling back to the global registry, allowing route templates to reference 
their own beans.
    
    Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
    
    * CAMEL-23550 Add test cases for local-only bean lookup and local/global 
bean conflict
    
    ---------
    
    Co-authored-by: Claude Sonnet 4.5 <[email protected]>
---
 .../org/apache/camel/reifier/AbstractReifier.java  | 16 +++++
 .../camel/builder/RouteTemplateLocalBeanTest.java  | 74 ++++++++++++++++++++++
 2 files changed, 90 insertions(+)

diff --git 
a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/AbstractReifier.java
 
b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/AbstractReifier.java
index 2a6d196213d9..f7e32a4740ea 100644
--- 
a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/AbstractReifier.java
+++ 
b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/AbstractReifier.java
@@ -25,11 +25,14 @@ import java.util.Set;
 import org.apache.camel.CamelContext;
 import org.apache.camel.Endpoint;
 import org.apache.camel.Expression;
+import org.apache.camel.NamedNode;
 import org.apache.camel.NoSuchBeanException;
 import org.apache.camel.NoSuchEndpointException;
 import org.apache.camel.Predicate;
 import org.apache.camel.Route;
+import org.apache.camel.RouteTemplateContext;
 import org.apache.camel.model.ExpressionSubElementDefinition;
+import org.apache.camel.model.RouteDefinition;
 import org.apache.camel.model.language.ExpressionDefinition;
 import org.apache.camel.reifier.language.ExpressionReifier;
 import org.apache.camel.spi.BeanRepository;
@@ -208,6 +211,19 @@ public abstract class AbstractReifier implements 
BeanRepository {
         if (EndpointHelper.isReferenceParameter(name)) {
             answer = EndpointHelper.resolveReferenceParameter(camelContext, 
name, type, false);
         }
+        if (answer == null && route != null) {
+            // check local bean repository from route template context first
+            NamedNode routeNode = route.getRoute();
+            if (routeNode instanceof RouteDefinition routeDef) {
+                RouteTemplateContext rtc = routeDef.getRouteTemplateContext();
+                if (rtc != null) {
+                    BeanRepository localRepo = rtc.getLocalBeanRepository();
+                    if (localRepo != null) {
+                        answer = localRepo.lookupByNameAndType(name, type);
+                    }
+                }
+            }
+        }
         if (answer == null) {
             // fallback to use registry which allows tooling to influence 
reifier that uses beans or classes
             answer = getRegistry().lookupByNameAndType(name, type);
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/builder/RouteTemplateLocalBeanTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/builder/RouteTemplateLocalBeanTest.java
index 114a311d1f57..f4dd6e8f6838 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/builder/RouteTemplateLocalBeanTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/builder/RouteTemplateLocalBeanTest.java
@@ -69,6 +69,80 @@ public class RouteTemplateLocalBeanTest extends 
ContextTestSupport {
         context.stop();
     }
 
+    @Test
+    public void testLocalBeanFoundByReifier() throws Exception {
+        // Test that AbstractReifier can find a local bean (kamelet scenario)
+        // Local bean is defined via templateBean, NOT in global registry
+        context.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() {
+                
routeTemplate("myTemplate").templateParameter("foo").templateParameter("bar")
+                        .templateBean("myLocalBean",
+                                (Processor) ex -> 
ex.getMessage().setBody("LocalOnly " + ex.getMessage().getBody()))
+                        .from("direct:{{foo}}")
+                        .to("bean:{{bar}}");
+            }
+        });
+
+        context.start();
+
+        TemplatedRouteBuilder.builder(context, "myTemplate")
+                .parameter("foo", "one")
+                .parameter("bar", "myLocalBean")
+                .routeId("myRoute")
+                .add();
+
+        assertEquals(1, context.getRoutes().size());
+
+        // AbstractReifier should find the local bean and use it
+        Object out = template.requestBody("direct:one", "World");
+        assertEquals("LocalOnly World", out);
+
+        // Bean should NOT be in global registry (kamelet local beans are 
scoped to route template)
+        assertNull(context.getRegistry().lookupByName("myLocalBean"));
+
+        context.stop();
+    }
+
+    @Test
+    public void testLocalBeanOverridesGlobalBean() throws Exception {
+        // Test that local bean takes precedence when both local and global 
beans exist with same name
+        // This ensures AbstractReifier checks local repository BEFORE global 
registry
+
+        // Register a global bean with the same name
+        context.getRegistry().bind("myBar", (Processor) ex -> 
ex.getMessage().setBody("Global " + ex.getMessage().getBody()));
+
+        context.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() {
+                
routeTemplate("myTemplate").templateParameter("foo").templateParameter("bar")
+                        .from("direct:{{foo}}")
+                        .to("bean:{{bar}}");
+            }
+        });
+
+        context.start();
+
+        // Create route with local bean that has the same name as global bean
+        TemplatedRouteBuilder.builder(context, "myTemplate")
+                .parameter("foo", "one")
+                .parameter("bar", "myBar")
+                .bean("myBar", (Processor) ex -> 
ex.getMessage().setBody("Local " + ex.getMessage().getBody()))
+                .routeId("myRoute")
+                .add();
+
+        assertEquals(1, context.getRoutes().size());
+
+        // The local bean should take precedence over the global bean
+        Object out = template.requestBody("direct:one", "World");
+        assertEquals("Local World", out);
+
+        // Global bean should still exist in registry
+        assertNotNull(context.getRegistry().lookupByName("myBar"));
+
+        context.stop();
+    }
+
     @Test
     public void testLocalBeanInBuilder() throws Exception {
         context.addRoutes(new RouteBuilder() {

Reply via email to