allthingssecurity opened a new pull request, #27466: URL: https://github.com/apache/camel/pull/27466
# Description [CAMEL-25068](https://issues.apache.org/jira/browse/CAMEL-25068) item 1 Follow-up from the deep review of CAMEL-25048. When the caller binds a bean with the same name as a `templateBean` of the template, which of the two beans the route gets depended on how the caller bound it and on how the route looks it up. Template: ```java routeTemplate("myTemplate").templateParameter("foo") .templateBean("greeting", Processor.class, rtc -> ...) // sets the body to "template" .from("direct:{{foo}}") .process("greeting"); ``` On `main`: | The caller binds `greeting` with | `process("greeting")` (lookup by `Processor`) | `to("bean:{{greeting}}")` (lookup by name) | |---|---|---| | `TemplatedRouteBuilder...bean("greeting", mine)` | template | caller | | `TemplatedRouteBuilder...bean("greeting", Processor.class, mine)` | template | template | | `TemplatedRouteDefinition.bean("greeting", mine)` (`templatedRoute` in Java, XML, YAML) | template | caller | | `TemplatedRouteBuilder...configure(rtc -> rtc.bind("greeting", Processor.class, mine))` | caller | caller | The caller's beans are bound in the route template context before `DefaultModel.doAddRouteFromTemplate`, which then binds the template beans into the same local registry (`addTemplateBeans`). The registry keeps one entry per name and type, so a template bean with the same type replaces the caller's bean, and one with another type is added next to it; a lookup by type then finds the template bean, and a lookup by name finds whichever entry was bound first. A configurer runs later, when the route is created, so its bean replaces the template bean of the same type. This change implements option (a) from the JIRA analysis: the caller's bean wins. `addTemplateBeans` skips a template bean whose name the caller has already bound, so the template bean is not created and every lookup finds the caller's bean. This is consistent with: - the configurer (and CAMEL-25048 item 6, where the configurer of the `TemplatedRouteBuilder` runs after the one of the template, so it can override it); - template parameters, where the caller's value overrides the default value of the template; - replacing a template bean with a mock in a test. Kamelets are not affected: `addRouteFromKamelet` creates a new route template context with parameters only, so no template bean is skipped there (camel-kamelet suite below). Other options, for the review: - (b) the template bean wins: document it, and bind the template beans after the configurers so that the configurer path agrees. The template author keeps control; the caller cannot replace a template bean. - (c) fail with `FailedToCreateRouteFromTemplateException` on a clash. Strict, and it breaks callers that override on purpose. Behaviour change: the upgrade guide (4.23, "Route templates") gets one more item, and `route-template.adoc` (section "Binding Beans to Route Templates") a sentence. The javadoc of the three `TemplatedRouteBuilder.bean` methods now says that the bean takes precedence over a template bean with the same name. Not changed: - A configurer that binds the name without a type (`rtc.bind("greeting", mine)`, keyed by the class of `mine`) after the template bean is bound still loses a lookup by the template bean's type, as on `main`. Making that path agree too would need `DefaultRouteTemplateContext.bind` to replace every entry of the name, which changes the registry semantics; I left it out. Happy to add it if you prefer. - One `TemplatedRouteBuilder` (or `RouteTemplateContext`) used to add several routes: the template beans bound for the first route are in its local registry when the next route is added, so they are now kept for the next route instead of bound again. Camel itself always uses a new context per route (`TemplatedRouteBuilder.builder`, `addRouteFromTemplatedRoute`, the parameter map variants of `addRouteFromTemplate`, Kamelets). The precedence rule was checked with a small Lean 4 model of `SimpleRegistry.bind` / `SupplierRegistry.lookupByNameAndType` and the three binding steps (caller, template, configurer). It reproduces the four rows above, proves that with the change every lookup of a name the caller bound (by any type) returns the caller's bean, and that the change binds exactly what `main` binds when no template bean has a name the caller bound. It also shows the configurer-without-type case above. Tests: `RouteTemplateCallerBeanTest` (camel-core), one test per binding path: - `builderBeanTakesPrecedence`: `TemplatedRouteBuilder.bean` without and with a type; also checks that the template bean with the same name is not created, and that the other template bean (`suffix`) is still used; - `templatedRouteBeanTakesPrecedence`: `TemplatedRouteDefinition.bean` via `addRouteFromTemplatedRoute`; - `configurerBeanTakesPrecedence`: `configure(rtc -> rtc.bind(...))`. The first two fail on `main` (two runs each): `expected: "caller!" but was: "template!"`. The configurer test passes on `main`: it pins the path the change aligns with. With the change: - the camel-core suite passes (8090 tests, 0 failures, 45 skipped; `FileConsumerIdempotentKeyNameAndSizeTest` failed once and passed on the rerun), and so do the suites of the core modules it is built with (9454 tests in total); - camel-kamelet (all 64 test classes, 87 tests, 0 failures, 3 skipped); - the route template, templated route, Kamelet and reload tests of camel-yaml-dsl (12 classes, 56 tests) and camel-xml-io-dsl (6 classes, 16 tests), 0 failures. # Target - [x] I checked that the commit is targeting the correct branch (Camel 4 uses the `main` branch) # Tracking - [x] If this is a large change, bug fix, or code improvement, I checked there is a [JIRA issue](https://issues.apache.org/jira/browse/CAMEL) filed for the change (usually before you start working on it). # Apache Camel coding standards and style - [x] I checked that each commit in the pull request has a meaningful subject line and body. - [ ] I have run `mvn clean install -DskipTests` locally from root folder and I have committed all auto-generated changes. (I built and tested the core modules and the modules listed above, including the formatter and import-sort plugins. No generated files change. I did not run the full root build.) # AI-assisted contributions - [x] If this PR includes AI-generated code, commits have proper co-authorship attribution (e.g., `Co-authored-by` trailers) and the PR description identifies the AI tool used. This PR was prepared with Claude Code (Claude Opus 5.5). The commit carries a `Co-Authored-By` trailer. _Claude Code on behalf of allthingssecurity_ 🤖 Generated with [Claude Code](https://claude.com/claude-code) -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
