[
https://issues.apache.org/jira/browse/CAMEL-25678?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Work on CAMEL-25678 started by shashank.
----------------------------------------
> camel-core - Switch EIP case values and the Dynamic Router uriDelimiter do
> not resolve property placeholders, so a case value with a placeholder never
> matches and the slip is not split
> ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
> Key: CAMEL-25678
> URL: https://issues.apache.org/jira/browse/CAMEL-25678
> Project: Camel
> Issue Type: Bug
> Components: camel-core
> Reporter: shashank
> Assignee: shashank
> Priority: Major
>
> Every String option of an EIP is passed through property-placeholder
> resolution when the route is created ({{AbstractReifier.parseString}}); this
> is also how route template and Kamelet parameters reach an EIP. Two options
> are used as written instead.
> h3. 1. Switch EIP: the case value
> {{SwitchReifier.createProcessor}} (main cd2ce899764e, lines 51-56) builds the
> dispatch table from {{c.getValue().toLowerCase(Locale.ENGLISH)}}. The {{uri}}
> of the case and of {{otherwise}} goes through {{staticUri}}, which calls
> {{parseString}}, but the value does not. A case such as
> {code:java}
> from("direct:tickets")
> .doSwitch(header("tier"))
> .doCase("{{gold.code}}", "direct:gold")
> .otherwise("direct:standard");
> {code}
> is keyed by the text \{\{gold.code\}\}. No selector result matches it (only a
> header that literally contains the text \{\{gold.code\}\} does), so every
> message goes to {{otherwise}}, or continues after the Switch without a
> destination when there is no {{otherwise}}. Nothing is logged. The same
> happens in XML and YAML, and for a route template or Kamelet parameter used
> as a case value (doCase("\{\{tier\}\}", ...) in a {{routeTemplate}}), where a
> placeholder is the only way to pass the parameter. The duplicate check also
> compares the unresolved text, so two cases that resolve to the same value are
> not rejected at startup as the documentation says.
> The Switch documentation says that case and fallback URIs support property
> placeholders and that values are "literal"; in the design (CAMEL-24988)
> "literal" is used in contrast to patterns and wildcards. It does not say that
> values do not support placeholders.
> h3. 2. Dynamic Router EIP: uriDelimiter
> {{DynamicRouterReifier.createProcessor}} (lines 36-37) uses
> {{definition.getUriDelimiter()}} as written. {{RoutingSlipReifier}} (line 38)
> and {{RecipientListReifier}} (line 56) resolve their delimiter with
> {{parseString}}. With uriDelimiter("\{\{delim\}\}") and a slip
> {{"mock:a;mock:b"}}, the slip is not split and the exchange is sent to one
> endpoint whose uri is the whole slip (for {{mock:}}, a mock named
> {{a;mock:b}}); with other components it fails or sends to an unexpected
> endpoint.
> h3. Reproduction
> New tests in camel-core; on main:
> * {{SwitchEndpointTest.caseValueResolvesPropertyPlaceholder}}:
> doCase("\{\{switch.tier\}\}", "mock:gold") with {{switch.tier=gold}}, headers
> {{gold}}, {{GOLD}} and the literal text \{\{switch.tier\}\}: {{mock://gold
> Body of message: 0. Expected: <first> but was: <third>}} (only the literal
> placeholder text matched).
> * {{SwitchEndpointTest.caseValueResolvesRouteTemplateParameter}}: a route
> template with doCase("\{\{tier\}\}", "mock:gold") and {{tier=silver}}:
> {{mock://gold Body of message: 0. Expected: <first> but was: <second>}}.
> * {{SwitchValidationTest.rejectsDuplicateValuesAfterResolvingPlaceholders}}:
> doCase("\{\{switch.tier\}\}", ...) and {{doCase("gold", ...)}} start without
> error: {{Expected java.lang.Exception to be thrown, but nothing was thrown.}}
> * {{DynamicRouterUriDelimiterPlaceholderTest}}: a slip {{mock:a;mock:b}} with
> uriDelimiter("\{\{slip.delimiter\}\}") and {{slip.delimiter=;}}: {{mock://a
> Received message count. Expected: <1> but was: <0>}}.
> h3. Proposed fix
> Resolve both with {{parseString}} in the reifier: the case value before it is
> lower-cased (and before the duplicate check), the {{uriDelimiter}} before the
> default is applied. Values without placeholders are unchanged. A placeholder
> of a property that does not exist then fails the route at startup, as it does
> for the other options.
> Not changed, same pattern, smaller impact (follow-ups if wanted):
> {{RollbackReifier}} uses {{message}} as written (only the text of the
> exception), and {{TransformDataTypeReifier}} uses {{fromType}}/{{toType}} as
> written (fails at startup with "No transformer").
> How it was found: a Lean 4 model of the Switch dispatch table (case value,
> placeholder resolution, case folding) against the Switch documentation: on
> main no selector result can select a case whose value contains a placeholder,
> and with the value resolved before folding the table matches the
> documentation for every value; the counterexample is checked by {{decide}}. A
> follow-up sweep of all reifiers for String options that are not passed to
> {{parseString}} found the Dynamic Router delimiter. The model is a sketch;
> the tests are the evidence.
> Affected: main (cd2ce899764e; tested). Switch: camel-4.23.x (same line 54,
> read, not run); the Switch EIP is not on camel-4.22.x and older. Dynamic
> Router: camel-4.23.x, camel-4.22.x, camel-4.18.x and camel-4.14.x have the
> same lines 36-37 (read, not run).
> Duplicate check (2026-10-15): JIRA text "uriDelimiter" (only CAMEL-25083,
> iterating a delimiter-only string), "switch case value placeholder",
> "dynamicRouter placeholder", summaries with "placeholder" since June 2026
> (CAMEL-24414, CAMEL-24282, CAMEL-24696 and others, none about these options);
> GitHub pull requests "Switch EIP", "uriDelimiter", "SwitchReifier" (nothing
> open or related).
> _Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v8.20.10#820010)