Repository navigation
CAMEL-25494: camel-yaml-io - write the onException, onCompletion and interceptors of a route configuration as the YAML DSL loads them - #27629
Conversation
…interceptors of a route configuration as the YAML DSL loads them Each item of these lists is written as a one-key map (- onException: ...), as the YAML DSL reads them (wrapItem = true in RouteConfigurationDefinitionDeserializer). The uri of interceptFrom and interceptSendToEndpoint is a pattern and is no longer split into parameters, which their YAML DSL schema does not have. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
🌟 Thank you for your contribution to the Apache Camel project! 🌟 🐫 Apache Camel Committers, please review the following items:
|
gnodet-bot
left a comment
There was a problem hiding this comment.
Correct, well-tested fix for a real YAML round-trip bug. The writer now wraps route-configuration child items (onException, onCompletion, intercept, interceptFrom, interceptSendToEndpoint) exactly as the YAML DSL deserializer expects them, and the keepUriPattern fix prevents interceptor URI patterns from being split into scheme+parameters. ✅
This review was generated by an AI agent, Hermès on behalf of @gnodet.
| // as the route configurations are dumped by camel.main.dumpRoutes, which camel validate normalize uses | ||
| RouteConfigurationsDefinition configs = new RouteConfigurationsDefinition(); | ||
| configs.getRouteConfigurations().addAll(model.getRouteConfigurationDefinitions()); | ||
| String yaml = new LwModelToYAMLDumper().dumpModelAsYaml(context, configs, false, true, false, false); |
There was a problem hiding this comment.
💡 Minor suggestion — test coverage: The test currently only covers the uriAsParameters=true path (the second boolean in the dumpModelAsYaml call). Consider adding a second assertion with uriAsParameters=false to confirm the non-expanded URI form also round-trips correctly through the YAML DSL loader. Low risk since the wrapped-item fix is independent of URI expansion, but it would ensure both paths are validated.
| String yaml = new LwModelToYAMLDumper().dumpModelAsYaml(context, configs, false, true, false, false); | |
| String yaml = new LwModelToYAMLDumper().dumpModelAsYaml(context, configs, false, true, false, false); | |
| String yamlNoParams = new LwModelToYAMLDumper().dumpModelAsYaml(context, configs, false, false, false, false); |
|
🧪 CI tested the following changed modules:
🔬 Scalpel shadow comparison — Scalpel: 589 of 704 tested, 27 compile-only — current: 70 all testedMaveniverse Scalpel detected 589 affected modules (current approach: 70). Skip-tests mode would test 589 modules (3 direct + 587 downstream), skip tests for 27 (generated code, meta-modules)
|
| Module | Duration | Status |
|---|---|---|
| Camel :: YAML DSL | 14.3s | SUCCESS |
| Camel :: Maven Plugins :: Camel Maven Package | 12.3s | SUCCESS |
| Camel :: YAML IO | 6.6s | SUCCESS |
Top 20 slowest modules:
Camel :: YAML DSL(14.3s)Camel :: Maven Plugins :: Camel Maven Package(12.3s)Camel :: YAML IO(6.6s)
davsclaus
left a comment
There was a problem hiding this comment.
Thanks Federico, nice catch, and a clean fix.
What I checked:
- The bug is real.
RouteConfigurationDefinitionDeserializeris the only YAML deserializer withwrapItem = true, on exactly these five properties, and the JSON schema has each item as a one-key map (additionalProperties: false). So the written form- onException: ...is the only form the loader and schema accept. It is also the form the docs use (for exampleoncompletion.adoc). The rest of the output stays in the canonical YAML form (constant: expression:,to: uri:). - Round trip: the new
RouteConfigurationYamlDumpTestdumps withuriAsParameters=true, asdumpRoutes/validate normalizedo, and loads the dump back throughYamlTestSupport, which also validates it against the schema. Without the wrapping it fails with "Node should have only 1 key", and withoutkeepUriPatternthe schema rejectsparameters(the schema ofinterceptFrom/interceptSendToEndpointonly hasuri). So the test fails without each half of the fix. keepUriPatternis right to keep the uri as written: it is a pattern, not an endpoint uri.expandUrialways putsurifirst, so overwriting it keeps the key order.afterUriis unaffected because it goes through another key.- XML writer consistency: camel-xml-io does not have this gap. In XML the items of a
<routeConfiguration>are bare<onException>,<onCompletion>, ... elements, whichModelWriter.doWriteRouteConfigurationDefinitionalready writes withdoWriteList(null, "onException", ...).LwModelToXMLDumperhas nouriAsParametersmode, so the interceptor pattern can't be split there either. The two writers now each write their own DSL's form. - No jbang command (
RouteDslConverter,TransformRoute,YamlNormalizeCommand) post-processes the route configuration output, so nothing ends up double-wrapped. - This follows the same template approach as
$yamlKeysfrom CAMEL-25255. No upgrade-guide entry is needed, because the old output could not be loaded at all.
Two optional follow-ups, inline. Neither blocks this PR.
CI is green.
This review was generated by an AI agent (Claude Code on behalf of Claus Ibsen) and may contain inaccuracies. Please verify all suggestions before applying.
| #set( $yamlKeys = { "VerbDefinition.params": "param", "VerbDefinition.responseMsgs": "responseMessage", "RouteTemplateDefinition.templateParameters": "parameters", "RouteTemplateDefinition.templateBeans": "beans" } ) | ||
| ## the YAML DSL reads each item of some lists as a one-key map named after the list (wrapItem = true in the YAML DSL | ||
| ## deserializer), such as - onException: ... in a route configuration (keyed by class.member) | ||
| #set( $wrapItems = [ "RouteConfigurationDefinition.intercepts", "RouteConfigurationDefinition.interceptFroms", "RouteConfigurationDefinition.interceptSendTos", "RouteConfigurationDefinition.onCompletions", "RouteConfigurationDefinition.onExceptions" ] ) |
There was a problem hiding this comment.
Optional: this list repeats the wrapItem = true properties of RouteConfigurationDefinitionDeserializer by hand, as $yamlKeys does for the renamed lists, so the two can drift apart if another YAML property gets wrapItem later. A small guard test in camel-yaml-dsl (or a comment on the @YamlPropertys of the deserializer pointing back here) would catch that. Fine to leave for later.
| .satisfies(i -> assertThat(i.getUri()).isEqualTo("mock:result*")); | ||
| assertThat(config.getInterceptFroms()).singleElement() | ||
| .satisfies(i -> assertThat(i.getUri()).isEqualTo("direct*")); | ||
| assertThat(config.getIntercepts()).hasSize(1); |
There was a problem hiding this comment.
Optional: onCompletion and intercept only get a size check, and handled and the steps are not checked. A stronger check, the one YamlRoundTripTest (camel-yaml-dsl-validator) uses, is to dump the route configuration with LwModelToXMLDumper before and after the reload and compare the two strings. That catches any field that gets lost on the way. A route-configuration variant of YamlRoundTripTest over errorHandlerConfiguration*.xml could be a follow-up too.
…e round trip test covers the others Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Trimmed in ff9851c: Claude Code on behalf of Croway |
JIRA: https://issues.apache.org/jira/browse/CAMEL-25494
Problem
The YAML route dump (
camel.main.dumpRoutes=yaml, used bycamel validate normalize) writes theonExceptionitems of arouteConfigurationwithout theironException:key:camel validate yamlrejects it (property 'exception' is not defined in the schema), andcamel runfails withNode should have only have 1 key, was: 3 keys. TheonCompletion,intercept,interceptFromandinterceptSendToEndpointlists of a route configuration have the same problem.Cause
The YAML DSL reads each item of these five lists as a one-key map named after the list (
wrapItem = trueinRouteConfigurationDefinitionDeserializer), but the generatedYamlModelWriterwrites them as lists of bare objects, as the XML DSL has them. The existing writer test (yaml-routeconfig.yaml) expected the wrong form.Fix
model-yaml-writer.vm(camel-package-maven-plugin) lists these members, as it already does for the YAML DSL names of other lists, and generatesdoWriteWrappedChildListfor them. The new helper inYamlModelWriterSupportwrites each item as- onException: ....YamlModelWriteris regenerated; only the five lines ofdoWriteRouteConfigurationDefinitionchange.uriAsParameters(ascamel validate normalizedumps), the uri pattern ofinterceptSendToEndpoint(such asmock:result*) was split intouri: mockandparameters: {name: result*}, which the schema ofinterceptSendToEndpointandinterceptFromdoes not allow (and a pattern is not an endpoint uri).LwModelToYAMLDumpernow writes the uri of these two interceptors as it is; the steps inside them are still written with parameters.Test
YamlModelWriterTest.testRouteConfiguration(camel-yaml-io) keeps itsonExceptionandinterceptitems, with the expectedyaml-routeconfig.yamlchanged to the form the YAML DSL loads (the five lists are covered by the round-trip test below).RouteConfigurationYamlDumpTest(camel-yaml-dsl) loads a route configuration with all five lists, dumps it ascamel.main.dumpRoutesdoes, and loads the dump back with the JSON schema validation ofYamlTestSupport.The camel-yaml-io and camel-yaml-dsl tests pass.
Related
Split out of CAMEL-25490 (#27609). Independent of it: #27609 changes how routes are dumped, this changes how route configurations are written. The fix applies to camel-4.22.x as well; a backport will follow once this is merged.
Claude Code on behalf of Croway